Všetko o používaní regulárnych výrazov v calibre¶
Regulárne výrazy sú funkcie používané na mnohých miestach v calibre na sofistikovanú manipuláciu s obsahom e-kníh a metadátami. Tento návod je jemným úvodom, ktorý vás naučí začať používať regulárne výrazy v calibre.
Najprv slovo varovania a slovo povzbudenia¶
Toto bude nevyhnutne trochu technické — napokon, regulárne výrazy sú technickým nástrojom na technické veci. Budem musieť použiť nejaký žargón a koncepty, ktoré sa môžu zdať komplikované alebo spletité. Pokúsim sa tieto koncepty vysvetliť čo najjasnejšie, ale naozaj sa bez ich použitia nezaobídem. Aj tak sa nenechajte odradiť žiadnym žargónom, pretože som sa pokúsil vysvetliť všetko nové. A hoci sa samotné regulárne výrazy môžu zdať ako tajomná čierna mágia (alebo, prozaickejšie, náhodný reťazec nezmyselných písmen a znakov), sľubujem, že nie sú až také komplikované. Aj tí, ktorí regulárnym výrazom naozaj dobre rozumejú, majú problém prečítať tie zložitejšie, ale ich písanie nie je také ťažké — výraz zostavujete krok za krokom. Takže urobte krok a poďte so mnou do králičej nory.
Kde v calibre môžete používať regulárne výrazy?¶
Existuje niekoľko miest, kde calibre používa regulárne výrazy. Je to Hľadať a nahradiť v možnostiach konverzie, zisťovanie metadát z názvov súborov v nastaveniach importu a Hľadať a nahradiť pri hromadnej úprave metadát kníh. Editor kníh calibre môže tiež používať regulárne výrazy vo svojej funkcii Hľadať a nahradiť. Nakoniec môžete regulárne výrazy používať pri vyhľadávaní v zozname kníh calibre a pri vyhľadávaní v prehliadači e-kníh calibre.
Čo je to vlastne regulárny výraz?¶
Regulárny výraz je spôsob, ako opísať množiny reťazcov. Jeden regulárny výraz môže zodpovedať viacerým rôznym reťazcom. To je to, čo robí regulárne výrazy takými výkonnými – sú stručným spôsobom, ako opísať potenciálne veľké množstvo variácií.
Poznámka
Slovo „reťazec“ tu používam v zmysle, v akom sa používa v programovacích jazykoch: reťazec jedného alebo viacerých znakov vrátane skutočných znakov, číslic, interpunkcie a takzvaných bielych znakov (zalomenia riadkov, tabulátory atď.). Upozorňujeme, že vo všeobecnosti sa veľké a malé písmená nepovažujú za rovnaké, takže „a“ je iný znak ako „A“ atď. V calibre sú regulárne výrazy v vyhľadávacom poli nerozlišujúce veľkosť písmen, ale v možnostiach konverzie áno. Existuje spôsob, ako dosiahnuť, aby každý regulárny výraz nerozlišoval veľkosť písmen, ale o tom budeme diskutovať neskôr. Je to komplikované, pretože regulárne výrazy umožňujú variácie v reťazcoch, ktorým zodpovedajú, takže jeden výraz môže zodpovedať viacerým reťazcom, a preto ich ľudia vôbec používajú. Viac o tom o chvíľu.
Môžete to vysvetliť?¶
No, preto sme tu. Po prvé, toto je najdôležitejší koncept regulárnych výrazov: Reťazec sám osebe je regulárny výraz, ktorý zodpovedá sám sebe. To znamená, že ak by som chcel pomocou regulárneho výrazu zodpovedať reťazcu "Hello, World!", regulárny výraz, ktorý by som použil, by bol Hello, World!. A áno, naozaj je to také jednoduché. Všimnete si však, že toto zodpovedá iba presnému reťazcu "Hello, World!", nie napríklad "Hello, wOrld!" alebo "hello, world!" alebo akejkoľvek inej takejto variácii.
To neznie tak zle. Čo ďalej?¶
Ďalej je začiatok naozaj dobrých vecí. Pamätáte si, kde som povedal, že regulárne výrazy môžu zodpovedať viacerým reťazcom? Tu to začína byť trochu komplikovanejšie. Povedzme, ako o niečo praktickejšie cvičenie, že e-kniha, ktorú ste chceli konvertovať, mala nepríjemnú pätu s počítaním strán, ako „Page 5 of 423“. Je zrejmé, že číslo stránky by stúpalo od 1 do 423, takže by ste museli zodpovedať 423 rôznym reťazcom, však? Nesprávne, v skutočnosti: regulárne výrazy vám umožňujú definovať množiny znakov, ktorým sa zodpovedá: Na definovanie množiny vložíte všetky znaky, ktoré chcete mať v množine, do hranatých zátvoriek. Takže napríklad množina [abc] by zodpovedala znaku „a“, „b“ alebo „c“. Množiny vždy zodpovedajú iba jednému zo znakov v množine. „Rozumejú“ rozsahom znakov, to znamená, že ak by ste chceli zodpovedať všetkým malým písmenám, použili by ste množinu [a-z], pre malé aj veľké písmená by ste použili [a-zA-Z] atď. Chápete? Takže samozrejme, pomocou výrazu Page [0-9] of 423 by ste dokázali zodpovedať prvým 9 stránkam, čím by sa počet potrebných výrazov znížil na tri: Druhý výraz Page [0-9][0-9] of 423 by zodpovedal všetkým dvojciferným číslam strán a som si istý, že uhádnete, ako by vyzeral tretí výraz. Áno, pokračujte. Napíšte ho.
Hej, super! Toto začína dávať zmysel!¶
Dúfal som, že to poviete. Ale pripravte sa, teraz to bude ešte lepšie! Práve sme videli, že pomocou množín sme mohli zodpovedať jednému z niekoľkých znakov naraz. Ale môžete dokonca opakovať znak alebo množinu, čím sa počet potrebných výrazov na spracovanie vyššie uvedeného príkladu s číslami strán zníži na jeden. Áno, JEDEN! Vzrušení? Mali by ste byť! Funguje to takto: Niektoré takzvané špeciálne znaky, „+“, „?“ a „*“, opakujú jediný prvok, ktorý im predchádza. (Prvok znamená buď jediný znak, množinu znakov, escape sekvenciu alebo skupinu (o posledných dvoch sa dozvieme neskôr) — v skratke akúkoľvek jedinú entitu v regulárnom výraze). Tieto znaky sa nazývajú zástupné znaky alebo kvantifikátory. Presnejšie, „?“ zodpovedá 0 alebo 1 predchádzajúcemu prvku, „*“ zodpovedá 0 alebo viac predchádzajúcim prvkom a „+“ zodpovedá 1 alebo viac predchádzajúcim prvkom. Niekoľko príkladov: Výraz a? by zodpovedal buď „“ (čo je prázdny reťazec, v tomto prípade nie príliš užitočný) alebo „a“, výraz a* by zodpovedal „“, „a“, „aa“ alebo akémukoľvek počtu a za sebou, a nakoniec výraz a+ by zodpovedal „a“, „aa“ alebo akémukoľvek počtu a za sebou (Poznámka: nezodpovedal by prázdnemu reťazcu!). To isté platí pre množiny: Výraz [0-9]+ by zodpovedal každému celému číslu, ktoré existuje! Viem, čo si myslíte, a máte pravdu: Ak to použijete vo vyššie uvedenom prípade porovnávania čísel strán, nebol by to ten jediný výraz na zodpovedanie všetkým číslam strán? Áno, výraz Page [0-9]+ of 423 by zodpovedal každému číslu stránky v tej knihe!
Poznámka
Poznámka k týmto kvantifikátorom: Vo všeobecnosti sa snažia zodpovedať čo najviac textu, takže pri ich používaní buďte opatrní. Nazýva sa to „nenásytné správanie“ — určite chápete prečo. Problém nastane, keď sa napríklad pokúsite zodpovedať značke. Zoberme si napríklad reťazec "<p class="calibre2">Title here</p>" a povedzme, že chcete zodpovedať otváracej značke (časť medzi prvým párom lomených zátvoriek, o značkách neskôr). Mysleli by ste si, že výraz <p.*> by zodpovedal tejto značke, ale v skutočnosti zodpovedá celému reťazcu! (Znak „.“ je ďalší špeciálny znak. Zodpovedá čomukoľvek okrem zalomení riadkov, takže v podstate výraz .* by zodpovedal akémukoľvek jednému riadku, na ktorý si spomeniete). Namiesto toho skúste použiť <p.*?>, ktorý robí kvantifikátor „*“ nenásytným. Tento výraz by zodpovedal iba prvej otváracej značke, ako sa zamýšľalo. V skutočnosti existuje aj iný spôsob, ako to dosiahnuť: Výraz <p[^>]*> bude zodpovedať tej istej otváracej značke — dôvod uvidíte po ďalšej sekcii. Len si všimnite, že pomerne často existuje viac ako jeden spôsob, ako napísať regulárny výraz.
No, tieto špeciálne znaky sú veľmi fajn, ale čo ak by som chcel zodpovedať bodke alebo otáznik?¶
To samozrejme môžete urobiť: Jednoducho vložte spätné lomítko pred akýkoľvek špeciálny znak a bude interpretovaný ako doslovný znak bez akéhokoľvek špeciálneho významu. Táto dvojica spätného lomítka nasledovaného jediným znakom sa nazýva escape sekvencia a akt vloženia spätného lomítka pred špeciálny znak sa nazýva escapovanie tohto znaku. Escape sekvencia sa interpretuje ako jediný prvok. Samozrejme existujú escape sekvencie, ktoré robia viac než len escapovanie špeciálnych znakov, napríklad "\t" znamená tabulátor. K niektorým escape sekvenciám sa dostaneme neskôr. A mimochodom, čo sa týka tých špeciálnych znakov: Považujte akýkoľvek znak, o ktorom v tomto úvode hovoríme, za znak s nejakou funkciou, ktorý je teda špeciálny a vyžaduje escapovanie, ak chcete doslovný znak.
Aké sú teda najužitočnejšie množiny?¶
Vedel som, že sa opýtate. Niektoré užitočné množiny sú [0-9] zodpovedajúca jedinému číslu, [a-z] zodpovedajúca jedinému malému písmenu, [A-Z] zodpovedajúca jedinému veľkému písmenu, [a-zA-Z] zodpovedajúca jedinému písmenu a [a-zA-Z0-9] zodpovedajúca jedinému písmenu alebo číslu. Môžete tiež použiť escape sekvenciu ako skratku:
\dje ekvivalentné s
[0-9]\wje ekvivalentné s
[a-zA-Z0-9_]\sje ekvivalentné s akýmkoľvek bielym znakom
Poznámka
„Biely znak“ je termín pre čokoľvek, čo sa nevytlačí. Tieto znaky zahŕňajú medzeru, tabulátor, posun riadku, posun stránky, návrat vozíka, pevné medzery atď.
Poznámka
Množiny veľkých a malých písmen môžu zodpovedať veľkým aj malým písmenám, ak je povolené nastavenie nerozlišovania veľkosti písmen pri vyhľadávaní. Takéto nastavenia sa nachádzajú napríklad v Nastavenia->Vyhľadávanie v samotnom calibre a na paneli Vyhľadávanie v calibre Prehliadač e-kníh, ako aj v nástroji calibre Upraviť knihu.
Ako poslednú poznámku k množinám, môžete tiež definovať množinu ako akýkoľvek znak okrem tých v množine. Urobíte to tak, že ako úplne prvý znak v množine uvediete znak "^". Takže [^a] by zodpovedal akémukoľvek znaku okrem „a“. Nazýva sa to doplnenie množiny. Tie skratky escape sekvencií, ktoré sme videli skôr, môžu byť tiež doplnené: "\D" znamená akýkoľvek nečíselný znak, čo je ekvivalentné s [^0-9]. Ostatné skratky môžu byť doplnené, uhádli ste, použitím príslušného veľkého písmena namiesto malého. Takže, keď sa vrátime k príkladu <p[^>]*> z predchádzajúcej sekcie, teraz môžete vidieť, že množina znakov, ktorú používa, sa snaží zodpovedať akémukoľvek znaku okrem zatváracej lomenej zátvorky.
Ale ak mám niekoľko rôznych reťazcov, ktorým chcem zodpovedať, veci sa komplikujú?¶
Nebojte sa, život je stále dobrý a jednoduchý. Zoberme si tento príklad: Kniha, ktorú konvertujete, má na každej nepárnej strane napísané „Title“ a na každej párnej strane napísané „Author“. Vyzerá to skvele v tlačenej podobe, však? Ale v e-knihách je to nepríjemné. Môžete zoskupiť celé výrazy do obyčajných zátvoriek a znak "|" vám umožní zodpovedať buď výrazu napravo od neho alebo výrazu naľavo od neho. Skombinujte to a máte hotovo. Príliš rýchle pre vás? Dobre, najprv zoskupíme výrazy pre nepárne a párne stránky, čím dostaneme (Title)(Author) ako naše dva potrebné výrazy. Teraz to zjednodušíme použitím zvislej čiary ("|" sa nazýva znak zvislej čiary): Ak použijete výraz (Title|Author), dostanete buď zhodu pre „Title“ (na nepárnych stranách), alebo zodpoviete „Author“ (na párnych stranách). No nebolo to jednoduché?
Samozrejme, zvislú čiaru môžete použiť aj bez zoskupovacích zátvoriek. Pamätáte si, keď som povedal, že kvantifikátory opakujú prvok, ktorý im predchádza? Nuž, zvislá čiara funguje trochu inak: Výraz „Title|Author“ bude tiež zodpovedať buď reťazcu „Title“, alebo reťazcu „Author“, rovnako ako vyššie uvedený príklad so zoskupením. Zvislá čiara vyberá medzi celým výrazom, ktorý jej predchádza a ktorý po nej nasleduje. Takže, ak by ste chceli zodpovedať reťazcom „Calibre“ a „calibre“ a chceli by ste vyberať iba medzi veľkým a malým „c“, museli by ste použiť výraz (c|C)alibre, kde zoskupenie zaručuje, že sa vyberie iba „c“. Ak by ste použili c|Calibre, dostali by ste zhodu s reťazcom „c“ alebo s reťazcom „Calibre“, čo nie je to, čo sme chceli. V skratke: Ak máte pochybnosti, použite zoskupenie spolu so zvislou čiarou.
Zabudli ste…¶
…počkať chvíľu, s skupinami sa dá urobiť ešte jedna naozaj skvelá vec. Ak máte skupinu, ktorej ste predtým zodpovedali, môžete použiť odkazy na túto skupinu neskôr vo výraze: Skupiny sa číslujú od 1 a odkazujete na ne escapovaním čísla skupiny, na ktorú chcete odkázať, takže piata skupina by bola odkazovaná ako \5. Takže, ak by ste hľadali ([^ ]+) \1 v reťazci „Test Test“, zodpovedali by ste celému reťazcu!
Na začiatku ste povedali, že existuje spôsob, ako dosiahnuť, aby regulárny výraz nerozlišoval veľkosť písmen?¶
Áno, povedal, ďakujem za pozornosť a pripomenutie. Môžete calibre povedať, ako chcete, aby sa určité veci spracúvali, pomocou niečoho, čo sa nazýva príznaky. Príznaky zahrniete do výrazu pomocou špeciálnej konštrukcie (?príznaky sem), kde samozrejme nahradíte „príznaky sem“ konkrétnymi príznakmi, ktoré chcete. Pre ignorovanie veľkosti písmen je príznak i, takže do výrazu zahrniete (?i). Takže (?i)test by zodpovedal „Test“, „tEst“, „TEst“ a akejkoľvek variácii veľkosti písmen, na ktorú si spomeniete.
Ďalší užitočný príznak umožňuje, aby bodka zodpovedala akémukoľvek znaku, vrátane zalomenia riadku, je to príznak s. Ak chcete použiť viacero príznakov vo výraze, jednoducho ich vložte do toho istého príkazu: (?is) by ignoroval veľkosť písmen a spôsobil, že bodka zodpovedá všetkému. Nezáleží na tom, ktorý príznak uvediete prvý, (?si) by bol ekvivalentný s vyššie uvedeným.
Myslím, že už začínam chápať tieto regulárne výrazy… ako ich používam v calibre?¶
Konverzie¶
Začnime nastaveniami konverzie, ktoré sú naozaj skvelé. V časti Hľadať a nahradiť môžete zadať regexp (skratka pre regulárny výraz), ktorý opisuje reťazec, ktorý bude počas konverzie nahradený. Skvelou časťou je sprievodca. Kliknite na palicu sprievodcu a získate náhľad toho, čo calibre počas procesu konverzie „vidí“. Posuňte sa nadol k reťazcu, ktorý chcete odstrániť, vyberte ho a skopírujte, vložte ho do poľa regexp v hornej časti okna. Ak existujú variabilné časti, ako napríklad čísla strán, použite množiny a kvantifikátory, aby ste ich pokryli, a zároveň nezabudnite escapovať špeciálne znaky, ak nejaké sú. Stlačte tlačidlo s označením Test a calibre zvýrazní časti, ktoré by nahradil, keby ste použili regexp. Keď ste spokojní, stlačte OK a konvertujte. Buďte opatrní, ak váš zdroj konverzie obsahuje značky ako v tomto príklade:
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
(bez hanby vytrhnuté z tohto vlákna). Museli by ste odstrániť aj niektoré značky. V tomto príklade by som odporučil začať značkou <b class="calibre2">, teraz musíte skončiť zodpovedajúcou zatváracou značkou (otváracie značky sú <tag>, zatváracie značky sú </tag>), čo je v tomto prípade jednoducho nasledujúca </b>. (Ak vám to nie je jasné, pozrite si dobrú HTML príručku alebo sa opýtajte na fóre). Otváracu značku možno opísať pomocou <b.*?>, zatváraciu značku pomocou </b>, takže by sme mohli odstrániť všetko medzi týmito značkami pomocou <b.*?>.*?</b>. Ale použitie tohto výrazu by bol zlý nápad, pretože odstraňuje všetko uzavreté v <b> značkách (ktoré, mimochodom, vykresľujú uzavretý text tučným písmom), a je veľký predpoklad, že týmto spôsobom odstránime časti knihy. Namiesto toho zahrňte aj začiatok uzavretého reťazca, čím vznikne regulárny výraz <b.*?>\s*Generated\s+by\s+ABC\s+Amber\s+LIT.*?</b>. \s s kvantifikátormi sú tu zahrnuté namiesto explicitného použitia medzier, ako vidno v reťazci, aby zachytili akékoľvek variácie reťazca, ktoré sa môžu vyskytnúť. Nezabudnite skontrolovať, čo calibre odstráni, aby ste sa uistili, že neodstránite žiadne časti, ktoré chcete zachovať, ak testujete nový výraz. Ak skontrolujete iba jeden výskyt, môžete prehliadnuť nezhodu niekde inde v texte. Tiež si všimnite, že ak omylom odstránite viac alebo menej značiek, než ste skutočne chceli, calibre sa po odstránení pokúsi poškodený kód opraviť.
Pridávanie kníh¶
Ďalšia vec, na ktorú môžete použiť regulárne výrazy, je extrahovanie metadát z názvov súborov. Túto funkciu nájdete v časti nastavení „Pridávanie kníh“. Je tu špeciálna funkcia: Môžete použiť názvy polí pre polia metadát, napríklad (?P<title>) by naznačovalo, že calibre používa túto časť reťazca ako názov knihy. Povolené názvy polí sú uvedené v oknách spolu s ďalším užitočným testovacím poľom. Príklad: Povedzme, že chcete importovať celú kopu súborov s názvami ako Classical Texts: The Divine Comedy by Dante Alighieri.mobi. (Očividne, toto už je vo vašej knižnici, keďže všetci milujeme klasickú taliansku poéziu) alebo Science Fiction epics: The Foundation Trilogy by Isaac Asimov.epub. Toto je očividne schéma pomenovania, z ktorej calibre nevytiahne žiadne zmysluplné údaje — jeho štandardný výraz na extrahovanie metadát je (?P<title>.+) - (?P<author>[^_]+). Regulárny výraz, ktorý tu bude fungovať, by bol [a-zA-Z]+: (?P<title>.+) by (?P<author>.+). Upozorňujeme, že vnútri skupiny pre pole metadát musíte použiť výrazy na opis toho, čomu pole skutočne zodpovedá. A tiež si všimnite, že pri používaní testovacieho poľa, ktoré calibre poskytuje, musíte k testovaciemu názvu súboru pridať príponu súboru, inak nezískate žiadne zhody, napriek použitiu funkčného výrazu.
Hromadná úprava metadát¶
Poslednou časťou je regulárny výraz Hľadať a nahradiť v poliach metadát. Môžete k nemu pristúpiť výberom viacerých kníh v knižnici a použitím hromadnej úpravy metadát. Pri používaní tejto poslednej funkcie buďte veľmi opatrní, pretože môže spôsobiť Veľmi zlé veci vašej knižnici! Pomocou testovacích polí dvakrát skontrolujte, či vaše výrazy robia to, čo chcete, a označte iba knihy, ktoré naozaj chcete zmeniť! V režime vyhľadávania regulárnych výrazov môžete vyhľadávať v jednom poli, nahradiť text niečím a dokonca zapísať výsledok do iného poľa. Praktický príklad: Povedzme, že vaša knižnica obsahovala knihy série Duna od Franka Herberta s názvami ako Dune 1 - Dune, Dune 2 - Dune Messiah atď. Teraz chcete dostať Dune do poľa série. Môžete to urobiť tak, že v poli názvu vyhľadáte (.*?) \d+ - .* a nahradíte ho výrazom \1 v poli série. Vidíte, čo som tam urobil? Je to odkaz na prvú skupinu, ktorou nahrádzate pole série. Teraz, keď máte sériu nastavenú, stačí už len ďalšie vyhľadávanie .*? - v poli názvu a nahradiť ho reťazcom "" (prázdny reťazec), opäť v poli názvu, a vaše metadáta sú čisté a upratané. Nie je to skvelé? Mimochodom, namiesto nahradenia celého poľa môžete k poľu tiež pripojiť alebo pred neho vložiť, takže ak by ste chceli, aby bol názov knihy doplnený o informácie o sérii na začiatku, mohli by ste to urobiť tiež. Ako ste si už určite všimli, existuje zaškrtávacie políčko s označením Rozlišovať veľkosť písmen, takže tu nebudete musieť používať príznaky na výber správania.
Tak, týmto sa takmer končí tento veľmi stručný úvod do regulárnych výrazov. Dúfam, že som vám ukázal dosť na to, aby ste mohli aspoň začať a aby ste mohli pokračovať v samoštúdiu — dobrým východiskovým bodom by bola dokumentácia k regulárnym výrazom jazyka Python.
Ešte posledné slovo varovania: Regexpy sú výkonné, ale tiež naozaj ľahké pokaziť. Calibre poskytuje naozaj skvelé možnosti testovania, aby ste zistili, či sa vaše výrazy správajú tak, ako očakávate. Používajte ich. Skúste sa nestreliť do nohy. (Bože, milujem tento výraz…). Ale ak by ste sa napriek varovaniu zranili na nohe (alebo na akýchkoľvek iných častiach tela), skúste sa z toho poučiť.
Rýchla referencia¶
Poďakovanie¶
Ďakujeme za pomoc s tipmi, opravami a podobne:
ldolse
kovidgoyal
chaley
dwanthny
kacir
Starson17
Orpheu
Viac o regexpoch nájdete v Používateľskej príručke Pythonu. Skutočná knižnica regulárnych výrazov, ktorú calibre používa, je: regex, ktorá podporuje niekoľko užitočných vylepšení oproti štandardnej knižnici Pythonu.
