Allt om att använda reguljära uttryck i calibre

Reguljära uttryck är funktioner som används på många ställen i calibre för att utföra avancerad manipulation av e-bokens innehåll och metadata. Den här handledningen är en mild introduktion till att få dig igång med att använda vanliga uttryck i calibre.

Först, ett varningens ord och ett modets ord

Detta kommer, oundvikligen, att vara något tekniska trots allt, reguljära uttryck är ett tekniskt verktyg för att göra tekniska saker. Jag kommer att behöva använda en del jargong och begrepp som kan verka komplicerat och invecklat. Jag ska försöka förklara dessa begrepp så tydligt som jag kan, men egentligen kan jag inte göra det utan att använda dem alla. Med detta sagt, förkasta inte detta på grund av all jargong, jag har försökt att förklara allt nytt. Och medan reguljära uttryck själva kan verka som en svårbegripliga, svart magi (eller för att vara mer prosaisk, en slumpad sträng av rappakalja bokstäver och tecken), jag lovar att det är inte så komplicerat. Även de som förstår vanliga uttryck riktigt bra kan ha problem med att läsa de mer komplexa, men att skriva dem är inte så svårt - du konstruerar uttrycket steg för steg. Så, ta ett steg och följa mig in i kaninhålet.

Var i calibre kan man använda reguljära uttryck?

Det finns ett fåtal platser calibre använder reguljära uttryck. Det finns Sök & ersätt i konverteringsalternativ, metadatadetektering från filnamn i importinställningar och Sök och ersätt när du redigerar metadata för böcker i grupp. calibres redigerare kan även använda reguljära uttryck i sin Sök och ersätt funktion. Slutligen kan du använda reguljära uttryck när du söker i calibre-boklistan och när du söker i calibre e-bokvisaren.

Vad i hela världen är ett reguljärt uttryck?

Ett reguljärt uttryck är ett sätt att beskriva en uppsättningar strängar. En enda reguljära uttryck kan matcha flera olika strängar. Det är det som gör reguljära uttryck så kraftfulla – de är ett kortfattad sätt att beskriva ett potentiellt stort antal varianter.

Observera

Jag använder sträng här i den mening den används i programspråk: en sträng av ett eller flera tecken, tecken inklusive faktiska tecken, siffror, skiljetecken och s.k. whitespace (radbrytningar, tabulatorer o.s.v.). Observera att i allmänhet anses inte stora och små bokstäver vara samma, alltså ”a” som en annan karaktär från ”A” och så vidare. I calibre, är reguljära uttryck skiftlägesokänslig i sökfältet, men inte i konverteringsalternativet. Det finns ett sätt att göra alla reguljära uttryck fall okänsligt, men vi kommer att diskutera det senare. Det blir komplicerat eftersom reguljära uttryck tillåter variationer i strängar som matchar, så ett uttryck kan matcha flera strängar, vilket är varför folk bryr sig att använda dem. Mer om det om ett tag.

Har du lust att förklara?

Tja, det är därför vi är här. För det första är detta det viktigaste konceptet i reguljära uttryck: En sträng i sig är ett reguljärt uttryck som matchar sig själv. Det vill säga, om jag ville matcha strängen "Hej, Värld!" genom att använda ett reguljärt uttryck, skulle det reguljära uttrycket för att använda vara Hej, Värld!. Och ja, det är verkligen så enkelt. Du kommer att märka dock att detta endast matchar den exakta strängen "Hej, Värld!", inte t.ex. "Hej vÄrlden!" eller "hej, värld!" eller någon annan sådan variation.

Det låter inte så illa. Vad kommer härnäst?

Nästa är början på riktigt bra grejer. Kom ihåg var jag sa att reguljära uttryck kan matcha flera strängar? Det är här det blir lite mer komplicerat. Säg, som en något mer praktisk övning, e-boken du ville konvertera hade en otäck sidfot som räknar sidor, ”Sida 5 av 423”. Uppenbarligen skulle sidnumret stiga från 1 till 423, så du skulle behöva matcha 423 olika strängar, eller hur? Fel, faktiskt: reguljära uttryck tillåter dig definiera uppsättningar av tecken som matchar: För att definiera en uppsättning, lägger du alla de tecken du vill att ska vara i uppsättningen inom hakparenteser. Så, till exempel uppsättningen `` [abc]`` skulle matcha antingen tecknet ”a”, ”b” eller ”c”. Uppsättningarna kommer alltid bara matcha en av karaktärerna i uppsättningen. De ”förstår” teckenformattering, det vill säga om du ville matcha mot alla små bokstäver, skulle du använda uppsättningen [az] för gemener och för versaler skulle du använda `` [a-zA-Z]`` o.s.v. Förstår du principen? Så, självklart, med hjälp av uttrycket Sida [0-9] av 423 skulle du kunna matcha de första nio sidorna, vilket minskar uttrycken som behövs för tre: Det andra uttrycket Sida [0-9] [0-9] av 423 skulle matcha alla tvåsiffriga sidnummer, och jag är säker på att du kan gissa hur det tredje uttryck skulle se ut. Ja, gå vidare. Skriv ner det.

Hej, snyggt! Detta börjar låta vettigt!

Jag hoppades att du skulle säga det. Men håll i dig själv, nu blir det ännu bättre! Vi såg precis att med uppsättning kan vi matcha en av flera tecken samtidigt. Men du kan även upprepa ett tecken eller uppsättning, för att minska antalet uttryck som behövs för att hantera ovan sidnummerexemplet till ett. Ja, ETT! Upphetsad? Du borde vara det! Det fungerar så här: Några så kallade specialtecken ”+”, ”?” och ”*”, * upprepa det enda elementet som föregår dem*. (Element betyder antingen ett enda tecken, en teckenuppsättning, en flyktsekvens eller en grupp (vi ska lära oss om de två sista senare) - kort sagt vilken enskild enhet som helst i ett reguljärt uttryck). Dessa tecken kallas jokertecken eller kvantifierare. För att vara mer exakt, ”?” matchar 0 eller 1 förekomster av det föregående elementet, ”*” matchar 0 eller flera för det föregående elementet och ”+” matchar 1 eller flera av det föregående elementet. Några exempel: Uttrycket a? skulle matcha antingen ”” (som är den tomma strängen, inte strikt användbar i detta fall) eller ”a”, uttrycket a* skulle matcha ””, ”a”, ”aa” eller valfritt antal a i rad, och slutligen uttrycket a+ skulle matcha ”a”, ”aa” eller valfritt antal a i rad (Observera: det skulle inte matcha den tomma strängen!). Samma gäller för uppsättningar: Uttrycket `` [0-9]+`` skulle matcha varje heltal som finns! Jag vet vad du tänker, och du har rätt: Om du använder fallet med matchande sidnummer ovan, skulle inte det vara det enda uttrycket för att matcha alla sidnummer? Ja, uttrycket Page [0-9]+ of 423 skulle matcha varje sidnummer i den boken!

Observera

En kommentar om dessa kvantifierare: De försöker i allmänhet att matcha så mycket text som möjligt, så var försiktig när du använder dem. Detta kallas ”girigt beteende” - Jag är säker på att du förstår varför. Det blir problematiskt när man, säg, försöker matcha en tagg. Tänk dig, till exempel strängen "<p class =" calibre2">Titel här</p>" och låt oss säga att du skulle vilja matcha öppningstaggen (delen mellan det första paret vinkelfästen, lite mer om taggar senare). Man skulle kunna tro att uttrycket <p.*> skulle matcha den taggen men faktiskt, den matchar hela strängen! (Tecknet ”.” Är ett annat specialtecken. Den matchar något utom radbrytningar, så i grund och botten, uttrycket .* Skulle matcha vilken rad du än kan tänka dig). Försök istället att använda <p.*?> som gör kvantifierare "*" ogiriga. Detta uttryck skulle endast matcha den första öppningstaggen, som avsett. Det finns faktiskt ett annat sätt att åstadkomma detta: Uttrycket <p[^>]*> matchar denna öppningstagg- du kommer se varför efter nästa avsnitt. Bara konstatera att det ganska ofta finns mer än ett sätt att skriva ett reguljärt uttryck.

Tja, dessa specialtecken är mycket snygga och allt, men vad händer om jag ville matcha en punkt eller ett frågetecken?

Du kan självklart göra det: Lägg bara ett bakåtsnedstreck framför valfritt specialtecken och det tolkas som det bokstavliga tecknet, utan någon speciell betydelse. Detta par av ett bakåtsnedstreck följt av ett enstaka tecken kallas en flyktsekvensen, och handlingen att sätta ett bakåtsnedstreck framför ett specialtecken kallas ett flykttecken. En flyktsekvens tolkas som ett enda element. Det finns givetvis flyktsekvensener som gör mer än att bara flykttecken, till exempel betyder "\t" en tabulator. Vi kommer till några av flyktsekvenserna senare. Åh, och förresten, angående dessa specialtecken: Betrakta alla tecken som vi diskuterar i den här introduktionen som att de har någon speciell funktion och därför måste flyktmarkeras om du vill ha det bokstavliga tecknet.

Så, vilka är de användbaraste uppsättningarna?

Visste att du skulle fråga. Några användbara uppsättningar är [0-9] matchar en enda siffra, [a-z] matchar en enda gemen, [A-Z] matchar en enda versal, [a-zA-Z] matchar en enda bokstav och [a-zA-Z0-9] matchar en enda bokstav eller siffra. Du kan också använda en flyktsekvens som stenografi:

\d

motsvarar [0-9]

\w

motsvarar [a-zA-Z0-9_]

\s

motsvarar alla whitespace

Observera

”Whitespace” är en term för allt som inte kommer att skrivas ut. Dessa tecken inkluderar blanksteg, tabulator, radmatning, formulärmatning, vagnretur, icke-brytande blanksteg o.s.v.

Observera

Uppsättningarna med versaler och gemener kan matcha både versaler och gemener om inställningen för att göra sökningar okänsliga för skiftlägen är aktiverad. Sådana inställningar finns, till exempel i Inställningar->Sökning i själva calibre och i sökpanelen i verktyget calibre e-bokvisaren samt calibre-verktyget Redigera bok.

Som en sista anteckning om uppsättningar kan du också definiera en uppsättning som valfritt tecken utom de i uppsättningen. Du gör det genom att inkludera tecknet "^" som det allra första tecknet i uppsättningen. Således skulle [^a] matcha alla tecken utom ”a”. Det kallas att komplettera uppsättningen. Dessa flyktsekvensstenografier som vi såg tidigare kan också kompletteras: "\D" betyder vilket tecken som helst som inte är numeriskt, och är alltså ekvivalent med [^0-9]. De andra stenografierna kan kompletteras med, du gissade rätt, att använda respektive versaler istället för gemener. Så, om du går tillbaka till exemplet <p[^>]*> från föregående avsnitt, kan du nu se att teckenuppsättningen den använder försöker matcha vilket tecken som helst förutom en avslutande vinkelparentes.

Men om jag hade några olika strängar jag ville matcha, blir saker komplicerade?

Frukta inte, livet är fortfarande bra och enkelt. Tänk på detta exempel: Boken du konverterar har ”Titel” skrivet på varje udda sida och ”Författare” skrivet på varje jämn sida. Ser bra i tryck, eller hur? Men i e-böcker är det irriterande. Du kan gruppera hela uttryck i normala parenteser och tecknet "|" låter dig matcha antingen uttrycket till höger eller det till vänster. Kombinera dem så är du klar. För snabbt för dig? Okej, först och främst grupperar vi uttryck för udda och jämna sidor och på så sätt får (Titel)(Författare) som våra två nödvändiga uttryck. Nu gör vi det enklare genom att använda det lodräta strecket ("|" kallas vertikala stapeltecknet): Om du använder uttrycket (Titel|Författare) får du antingen en träff för ”Titel” (på udda sidorna) eller så får du en träff för ”Författare” (på jämna sidorna). Var det inte lätt?

Du kan naturligtvis använda det lodräta strecket utan att använda grupperingsparenteser, lika så. Kommer du ihåg när jag sa att kvantifierare upprepar elementet som föregår dem? Tja, det vertikala strecket fungerar lite annorlunda: Uttrycket ”Titel|Författare” kommer också att matcha antingen strängen ”Titel” eller strängen ”Författare”, precis som ovanstående exempel med hjälp av gruppering. Det vertikala strecket väljer mellan hela uttrycket före och efter den. Så, om du ville matcha strängarna ”Calibre” och ”calibre” och ville bara välja mellan det övre och små bokstäver ”c”, skulle du behöva använda uttrycket (c|C)alibre, där grupperingen säkerställer att endast ”c” kommer att väljas. Om du skulle använda c|Calibre, du skulle få en match på strängen ”c” eller på strängen ”Calibre”, vilket inte är vad vi ville ha. Kort sagt: Om du är osäker, använd gruppering tillsammans med det vertikala strecket.

Du missade…

… vänta lite, det finns en sista, riktigt snygg sak du kan göra med uppsättningar. Om du har en uppsättning som du tidigare matchade kan du använda referenser till uppsättningen senare i uttrycket: Uppsättningar är numrerade med början 1, och du refererar till dem genom att flyktnumret på den uppsättning som du vill referera till, alltså den femte gruppen skulle kallad \5. Så, om du sökte ([^]+)\1 i strängen ”Test Test”, skulle du matcha hela strängen!

I början sa du att det fanns ett sätt att göra ett reguljärt uttryck skiftlägesokänsligt?

Ja, det gjorde jag, tack för att uppmärksammande och att du påminde mig. Du kan berätta för calibre hur du vill vissa saker hanteras med hjälp av något som kallas flaggor. Du inkluderar flaggor i ditt uttryck med hjälp av speciella konstruktionen (?flaggor finns här) där, naturligtvis, skulle du ersätta ”flaggor finns här” med de specifika flaggor du vill ha. För att ignorera teckenskiftläge finns flaggan i därmed inkluderar du (?i) i ditt uttryck. Således (?i)test skulle matcha ”Test”, ”tEst”, ”TEst”, och varje fall variation du kan tänka dig.

En annan användbar flagga låter punkten matcha vilket tecken som helst, inklusive den nyrad, flaggan s. Om du vill använda flera flaggor i en sats, lägg dem bara i samma sats: (?is) skulle ignorera skiftläge och göra att punkten matchar alla. Det spelar ingen roll vilken flagga som du anger först, (?si) skulle motsvara ovanstående.

Jag tror jag börjar förstå dessa reguljära uttryck nu… hur använder jag dem i calibre?

Konverteringar

Låt oss börja med konverteringsinställningarna, vilket är riktigt snyggt. I Sök- och ersättsdel, kan mata in en regexp (kort för reguljära uttryck) som beskriver den sträng som kommer att ersättas under konverteringen. Den nätta delen är guiden. Klicka på guiden och du får en förhandsvisning av vad calibre ”ser” under konverteringen. Bläddra ner till den sträng som du vill ta bort, välj och kopiera den, klistra in den i regexp fältet högst upp i fönstret. Om det finns variabla delar, t.ex. sidnummer eller så använder uppsättningar och kvantifierare för att täcka dem, och medan du ändå håller på, kom ihåg att undkomma specialtecken, om det finns några. Klicka på knappen Test och calibre belyser delarna som skulle ersättas om du använder regexp. När du är nöjd, klicka på OK och konvertera. Var försiktig om din konverteringskällan har taggar som detta exempel:

Maybe, but the cops feel like you do, Anita. What's one more dead vampire?
New laws don't change that. </p>
<p class="calibre4"> <b class="calibre2">Generated by ABC Amber LIT Conv
<a href="http://www.processtext.com/abclit.html" class="calibre3">erter,
http://www.processtext.com/abclit.html</a></b></p>
<p class="calibre4"> It had only been two years since Addison v. Clark.
The court case gave us a revised version of what life was

(skamlöst utslitet från denna tråd). Du skulle behöva ta bort en del av taggarna också. I detta exempel jag skulle rekommendera börjar med taggen <b class="calibre2">, nu måste du sluta med motsvarande sluttagg (öppningstaggar är <tag>, sluttaggar är </tag>), vilket är helt enkelt nästa </b> i detta fall. (Se en bra HTML-handboken eller fråga i forumet om du är osäker på den här punkten). Öppningstaggen kan vara beskrivas med <b.*?>, den avslutande taggen med hjälp av </b>, vilket vi kunde ta bort allt mellan dessa taggar med <b.*?>.*?</b>. Men att använda detta uttryck skulle vara en dålig idé, eftersom det tar bort allt omges av <b>- taggar (som förresten, återger den medföljande texten i fetstil), och det är en rimlig satsning som vi tar bort delar av boken på detta sätt. Istället inkluderar början av den medföljande strängen också, vilket gör det reguljära uttrycket <b.*?>\s*Skapa\s+genom\s+ABC\s+Amber\s+LIT.*?</b> Den \s med kvantifierare som ingår här i stället för explicit använda blanksteg som sedda i strängen för att fånga några varianter av strängen som kan uppstå. Kom ihåg att kontrollera vad calibre kommer att ta bort för att se till att du inte bort några delar som du vill behålla om du testar ett nytt uttryck. Om du bara kontrollera en händelse, kanske du missar en obalans någon annanstans i texten. Observera också att om du av misstag tar bort fler eller färre taggar än du faktiskt ville försöker calibre för att reparera den skadade koden efter att ha gjort borttagningen.

Lägga till böcker

En annan sak du kan använda reguljära uttryck för är att utvinna metadata från filnamn. Du hittar den här funktionen ”Lägga till böcker” i en del av inställningarna. Det finns en speciell funktion här: Du kan använda fältnamn för metadatafält, till exempel (?P<titel>) skulle indikera att calibre använder den här delen av strängen som boktitel. De tillåtna fältnamnen listas i fönstren, tillsammans med ett annat fint testfält. Ett exempel: Säg att du vill importera en hel massa filer som heter Klassiska texter: Den gudomliga komedin av Dante Alighieri.mobi. (Uppenbarligen finns detta redan i ditt bibliotek, eftersom vi alla älskar klassisk italiensk poesi) eller Science Fiction epos: Stiftelseserien av Isaac Asimov.epub. Detta är naturligtvis ett namngivningssystem som calibre inte kommer att utvinna några meningsfulla uppgifter ur - dess standarduttryck för att utvinna metadata är (?P<title>.+) - (?P<author>[^_]+). Ett reguljärt uttryck som fungerar här skulle vara [a-zA-Z]+: (?P<title>.+) by (?P<author>.+). Observera att i gruppen för metadatafältet måste du använda uttryck för att beskriva vad fältet faktiskt matchar. Och observera också att vid användning av testfältet calibre tillhandahåller måste du lägga till filändelsen till ditt testfilnamn, annars får du inga matchningar alls, trots att du använder ett fungerande uttryck.

Redigera metadata i grupp

Den sista delen är reguljära uttryck Sök och ersätt i metadatafält. Du kan komma åt detta genom att välja flera böcker i biblioteket och genom att redigera metadata i grupp. Var mycket försiktig när du använder den här sista funktionen, eftersom det kan göra mycket dåliga saker till ditt bibliotek! Dubbelkontrollera att dina uttryck verkligen gör vad du vill att de ska göra med hjälp av testfälten, och välj bara de böcker du verkligen vill ändra! I det sökläget för reguljära uttryck kan du söka i ett annat fält, ersätta texten med något och till och med skriva in resultatet i ett annat fält. Ett praktiskt exempel: Säg att ditt bibliotek innehöll böckerna i Frank Herberts Dune-serie, uppkallad efter stilen Dune 1 - Dune, Dune 2 - Dune Messiah och så vidare. Nu vill du få Dune in i seriefältet. Du kan göra det genom att söka efter \d+(*.?) -.* i titelfältet och ersätta det med \1 i seriefältet. Ser du vad jag gjorde där? Det är en referens till den första gruppen som du ersätter seriefältet med. Nu när du har serien klar behöver du bara göra en ny sökning efter .*? - i titelfältet och ersätta det med "" (en tom sträng), igen i titelfältet, och dina metadata är snygga och prydliga. Är inte det bra? Förresten, istället för att ersätta hela fältet kan du också lägga till eller låta föregå fältet, så om du ville att boktiteln ska infogas med serieinformation, kunde du göra det också. Som du vid det här laget utan tvekan har märkt, finns det en kryssruta markerad Skiftlägeskänslig, så att du inte behöver använda flaggor för att välja beteende här.

Nåväl, det avslutar nästan den mycket korta introduktionen till reguljära uttryck. Förhoppningsvis har jag ha visat dig tillräckligt för att åtminstone komma igång och så att du kan fortsätta lära dig själv - en bra utgångspunkt är Python-dokumentationen för reguljära uttryck.

Ett sista ord av varning, dock: Regexps är kraftfulla, men också väldigt lätta att få fel. calibre ger riktigt bra testmöjligheter för att se om dina uttryck beter sig som du förväntar dig. Använd dem. Försök att inte skjuta dig själv i foten. (Gud, jag älskar det uttrycket…). Men skulle du, trots varningen, skada din fot (eller andra kroppsdelar), försök att lära dig av det.

Snabbreferens

Förtjänst

Tack för hjälpen med tips, rättningar och sådant:

  • ldolse

  • kovidgoyal

  • chaley

  • dwanthny

  • kacir

  • Starson17

  • Orpheu

Mer information om regexps finns i Python-användarmanualen. Det verkliga reguljära uttrycksbiblioteket som används av calibre är: regex som stöder flera användbara förbättringar över ett Python-standardbibliotek.