Tutto sull’utilizzo delle espressioni regolari in calibre

Le espressioni regolari sono usate in molte parti di calibre per eseguire manipolazioni avanzate del contenuto e dei metadati degli e-book. Questa guida è un’introduzione amichevole all’uso delle espressioni regolari in calibre.

Per prima cosa, una parola di avviso e una di incoraggiamento

Questa guida sarà, per forza di cose, abbastanza tecnica - dopotutto, le espressioni regolari sono uno strumento tecnico che fa cose tecniche. Dovrò usare dei tecnicismi e dei concetti che potrebbero sembrare complicati o contorti. Farò del mio meglio per spiegare quei concetti il più chiaramente possibile, ma non posso proprio fare a meno di utilizzarli. Detto ciò, non essere scoraggiato da questo gergo, perché ho provato a spiegare tutto ciò che appare per la prima volta. E sebbene le espressioni regolari stesse possano sembrare una magia oscura e misteriosa (o, per essere più prosaici, segni e lettere astrusi messi a caso in una stringa senza senso), ti assicuro che non sono poi così complicati. Anche coloro che capiscono molto bene le espressioni regolari hanno problemi a leggere le più complesse tra di esse, ma scriverle non è così complicato - l’espressione è costruita passo passo. E allora, fai un passo avanti e seguimi nella tana del Bianconiglio

Dove è possibile utilizzare le espressioni regolari all’interno di calibre?

Ci sono vari luoghi in cui calibre utilizza le espressioni regolari. C’è Cerca e sostituisci nelle opzioni di conversione, l’estrazione dei metadati dai nomi dei file nelle impostazioni di importazione e il Cerca e sostituisci nella modifica di gruppo dei metadati dei libri. Anche l’editor di libri di calibre può usare le espressioni regolari nella sua funzione Cerca e sostituisci. Infine puoi usare le espressioni regolari quando cerchi nell’elenco dei libri di calibre e nel Lettore E-book di calibre.

Cosa diamine è un’espressione regolare?

Un’espressione regolare è un modo per descrivere insiemi di stringhe. Una singola espressione regolare può associare una serie di stringhe differenti. È questo che rende le espressioni regolari così potenti – sono un modo conciso per descrivere un numero potenzialmente alto di variazioni.

Nota

Qui uso stringa con il significato usato nei linguaggi di programmazione: una stringa di uno o più caratteri, che includono caratteri effettivi, numeri, punteggiatura e i cosiddetti «whitespace» (testo a capo, tabulazioni, ecc.). Ricorda che generalmente caratteri con maiuscole differenti non sono considerati uguali, ne deriva perciò che «a» è un carattere di verso da «A», e così via. In calibre, le espressioni regolari non fanno distinzione di maiuscole nella Barra di Ricerca, ma la fanno nelle opzioni di conversione. Esiste un modo per fare in modo che nessuna espressione regolare distingua le maiuscole, ma ne parleremo più avanti. Diventa complicato perché le espressioni regolari permettono varianti nelle stringhe che trovano, e quindi a un’espressione può corrispondere più di una stringa, che è poi la ragione per cui la gente si prende il disturbo di usarle. Più informazioni fra un attimo.

Potresti spiegare meglio?

Siamo qui per questo. Primo, e questo è il concetto più importante delle espressioni regolari: Una stringa presa da sola è un’espressione regolare che trova se stessa. Ovverosia, se volessi trovare la stringa "Ciao, Mondo!" usando un’espressione regolare, l’espressione regolare da usare sarebbe Ciao, Mondo!. E sì, è proprio così semplice. Ti sarai accorto, tuttavia, che questa espressione trova solo la stringa esatta "Ciao, Mondo!", non p.es. "Ciao, mOndo!" o "ciao, mondo!" o altre varianti del genere.

Non suona affatto male. E poi?

Poi inizia la parte davvero interessante. Ricordi quando ti ho detto che le espressioni regolari possono trovare più di una stringa? È qui che le cose si complicano. Poniamo, come esercizio un po” più concreto, che l’e-book che volevi convertire avesse un fastidioso piè di pagina con la conta delle pagine, come «Pagina 5 di 423». Ovviamente il numero di pagina salirebbe da 1 a 423, per cui dovresti trovare 423 stringhe differenti, giusto? Sbagliato in realtà: le espressioni regolari ti permettono di definire set di caratteri da trovare: per definirne uno, metti tutti i caratteri che vuoi avere nel set dentro parentesi quadre. Quindi, ad esempio, il set [abc] troverebbe sia il carattere «a», sia «b» sia «c». I set troveranno sempre solamente uno dei caratteri del set. Essi «riconoscono» gli intervalli, ovvero, se volessi trovare tutti i caratteri minuscoli dovresti usare il set [a-z], per tutti i caratteri minuscoli e maiuscoli dovresti usare [a-zA-Z], e così via. Chiaro il concetto? Quindi, ovviamente, usando l’espressione Pagina [0-9] di 423 saresti in grado di trovare le prime 9 pagine, riducendo quindi il numero di espressioni necessarie a tre: la seconda espressione Pagina [0-9][0-9] di 423 troverebbe tutti i numeri di pagina di due cifre, e sono sicuro che tu possa immaginare l’aspetto della terza espressione. Esatto, vai pure. Scrivila.

Ehi, ben fatto! Ora inizia ad avere un senso!

Speravo proprio che lo dicessi. Ma aspetta, ora diventa ancora più bello! Abbiamo appena visto che usando gli insiemi possiamo trovare un carattere tra molti inclusi. Ma puoi anche ripetere un carattere o un insieme, e ridurre così il numero di espressioni necessarie per gestire l’esempio dei numeri di pagina di poco fa a uno. Esatto, UNO! Eccitato? Dovresti esserlo! Funziona così: Alcuni cosiddetti caratteri speciali, «+», «?» e «*», ripetono l’elemento singolo che li precede. Per elemento si intende un singolo carattere, un insieme di caratteri, una sequenza di escape o un gruppo (Di questi ultimi due parleremo più avanti) – in breve ogni entità singola in un’espressione regolare. Questi caratteri sono chiamati wildcard o quantificatori. Per essere più precisi, «?» trova 0 o 1 dell’elemento che lo precede, «*» trova 0 o più dell’elemento che lo precede e «+» trova 1 o più dell’elemento che lo precede. Alcuni esempi: l’espressione a? troverebbe sia «» (che è la stringa vuota, non proprio utile nel nostro caso) sia «a», l’espressione a* troverebbe «», «a», «aa» o un qualsiasi numero di a messe in fila e, infine, l’espressione a+ troverebbe «a», «aa» o un qualsiasi numero di a messe in fila (Nota: non troverebbe la stringa vuota!). Lo stesso vale per gli insiemi: l’espressione [0-9]+ troverebbe ogni numero intero che c’è! So cosa stai pensando, e hai ragione: se usassi questa espressione nel caso di prima dei numeri di pagina, non sarebbe questa l’espressione unica che trova tutti i numeri di pagina? Sì, l’espressione Pagina [0-9]+ di 423 troverebbe tutti I numeri di pagina in quel libro!

Nota

Un appunto su questi quantificatori: di solito cercano di trovare la maggior quantità di testo possibile, quindi fai attenzione quando li usi. Questo è detto «comportamento vorace» - sono sicuro che capisci perché. Questo comportamento diventa problematico quando, poniamo, provi a trovare un tag. Considera per esempio la stringa "<p class="calibre2">Titolo qui</p>" e poniamo che tu voglia trovare il tag di apertura (la parte inclusa nella prima coppia di parentesi angolari, maggiori informazioni sui tag più avanti). Ti verrebbe da pensare che l’espressione <p.*> trovi quel tag, ma in realtà trova l’intera stringa! (Il carattere «.» è un altro carattere speciale. Trova ogni carattere tranne le interruzioni di riga quindi, in pratica, l’espressione .* troverebbe ogni singola linea immaginabile). Invece, prova a usare <p.*?> che rende il quantificatore "*" non vorace. Quell’espressione troverebbe solo il primo tag di apertura, come si voleva. C’è anche un altro modo per ottenere la stessa cosa, in realtà: l’espressione <p[^>]*> troverà lo stesso tag di apertura - capirai perché dopo la prossima sezione. Ricorda solo che c’è spesso più di un modo di scrivere un’espressione regolare.

Bene, questi caratteri speciali sono tutti molto graziosi, ma se volessi trovare un punto, o un punto di domanda?

Puoi farlo, naturalmente: Basta mettere una barra rovesciata prima di ogni carattere speciale e sarà interpretato come il carattere digitato, senza alcun significato speciale. Questa coppia di barra rovesciata seguita da un carattere singolo è chiamata sequenza di escape, e l’atto di mettere una barra rovesciata prima di un carattere speciale è detto (in inglese) «escaping the character». Una sequenza di escape è interpretata come un singolo elemento. Naturalmente ci sono sequenze di escape che fanno di più che rappresentare semplicemente i caratteri speciali, per esempio "\t" indica una tabulazione. Parleremo di alcune di queste sequenze di escape più avanti. Ah e comunque, riguardo a quei caratteri speciali: Considera che ognuno dei caratteri di cui discutiamo in questa introduzione perché hanno una certa funzione sia speciale, e che quindi abbia bisogno della barra di escape se vuoi il carattere digitato.

Quindi, quali sono i set più utili?

Sapevo che l’avresti chiesto. Alcuni utili set sono [0-9] che trova una singola cifra, [a-z] che trova una singola lettera minuscola, [A-Z] che trova una singola lettera maiuscola, [a-zA-Z] che trova una singola lettera e [a-zA-Z0-9] che trova una singola lettera o numero. Puoi anche usare una sequenza di escape per fare più in fretta:

\d

è equivalente a [0-9]

\w

è equivalente a [a-zA-Z0-9_]

\s

è equivalente a un qualunque spazio

Nota

Con «spazio» si intende qualsiasi cosa non venga stampata. Questi caratteri includono il normale spazio, il rientro (tabulazione), testo a capo, interruzione di pagina, ritorno a inizio riga, spazio unificatore, ecc.

Nota

I set di maiuscole e minuscole possono corrispondere sia alle maiuscole che alle minuscole se è abilitata l’impostazione per rendere le ricerche senza distinzione tra maiuscole e minuscole. Tali impostazioni si trovano, ad esempio, in Preferenze->Ricerca in calibre stesso e nel pannello di ricerca in calibre Visualizzatore di e-book così come nello strumento calibre Modifica libro.

Per concludere con i set, puoi anche definire un set con tutti i caratteri esclusi quelli nel set. Lo puoi fare includendo il carattere "^" come primo carattere del set. Così, [^a] troverebbe ogni carattere eccetto «a». Questo è detto integrare il set. Anche le sequenze di escape abbreviate che abbiamo visto in precedenza possono essere integrate: "\D" significa qualunque carattere non numerico, essendo perciò equivalente a [^0-9]. Le altre sequenze abbreviate possono essere integrate usando, hai indovinato, le rispettive lettere maiuscole invece di quelle minuscole. Quindi, tornando all’esempio <p[^>]*> della sezione precedente, ora puoi vedere che il set di caratteri utilizzato prova a trovare un qualsiasi carattere eccetto una parentesi angolare di chiusura.

Ma se avessi alcune stringhe diverse tra loro da trovare, diventerebbe complicato?

Niente paura, non c’è niente di più semplice. Considera questo esempio: Il libro che stai convertendo ha scritto «Titolo» su tutte le pagine dispari e «Autore» su tutte le pagine pari. Molto carino su carta, vero? Ma in un e-book, è fastidioso. Puoi raggruppare intere espressioni tra normali parentesi tonde, e il carattere "|" ti farà trovare o l’espressione alla sua destra o quella alla sua sinistra. Combinale ed è fatta. Ho spiegato troppo in fretta? Va bene, per prima cosa raggruppiamo le espressioni per le pagine pari e dispari, ottenendo così le due espressioni che ci servono (Titolo)(Autore). Ora rendiamo le cose più semplici usando la barra verticale ("|" è detto carattere di barra verticale): Se usi l’espressione (Titolo)|(Autore) troverai o un risultato per «Titolo» (nelle pagine dispari) o un risultato per «Autore» (nelle pagine pari). Abbastanza semplice, no?

Naturalmente puoi usare la barra verticale anche senza le parentesi di raggruppamento. Ricordi quando ho detto che i quantificatori ripetono l’elemento che li precede? Ecco, la barra verticale funziona in un modo leggermente diverso: Anche l’espressione «Titolo|Autore» troverà o la stringa «Titolo» o la stringa «Autore», esattamente come l’esempio precedente con il raggruppamento. La barra verticale sceglie tra l’intera espressione che la precede e quella che la segue. Quindi, se volessi trovare le stringhe «Calibre» e «calibre» e volessi distinguere solo tra la «c» maiuscola e minuscola, dovresti usare l’espressione (c|C)alibre, in cui il raggruppamento fa in modo che solo la «c» venga selezionata. Se invece avessi usato c|Calibre, avresti ottenuto una corrispondenza con la stringa «c» o con la stringa «Calibre», che non è quello che volevamo. In breve: Nel dubbio, usa il raggruppamento insieme alla barra verticale.

Ti sei dimenticato…

… fermo fermo fermo, c’è un’ultima cosa molto uitle che puoi fare con i gruppi. Se hai catturato un gruppo in precedenza, puoi riferirti a quel gruppo più avanti nell’espressione stessa: I gruppi sono numerati a partire da 1, e puoi riferirti ad essi con il loro numero. Il quinto gruppo, per esempio, sarebbe richiamato da \5. Quindi, se cercassi ([^ ]+) \1 nella stringa «Test Test», troveresti l’intera stringa!

All’inizio hai detto che c’era un modo di creare un’espressione regolare che non distingue le maiuscole?

Sì, l’ho fatto, grazie per aver prestato attenzione e avermelo ricordato. Puoi dire a Calibre come vuoi che certe cose vengano gestite usando qualcosa chiamato flag. Puoi includere i flag nella tua espressione utilizzando il costrutto speciale (?flags go here) dove, ovviamente, sostituirai «flags go here» con i flag specifici che desideri. Per ignorare le maiuscole e minuscole, il flag è i, quindi includi (?i) nella tua espressione. Pertanto, (?i)test corrisponderà a «Test», «tEst», «TEst» e qualsiasi variazione di maiuscole e minuscole a cui potresti pensare.

Another useful flag lets the dot match any character at all, including the newline, the flag s. If you want to use multiple flags in an expression, just put them in the same statement: (?is) would ignore case and make the dot match all. It doesn’t matter which flag you state first, (?si) would be equivalent to the above.

Penso di stare iniziando a capire queste espressioni regolari… Come le posso usare in calibre?

Conversioni

Let’s begin with the conversion settings, which is really neat. In the Search & replace part, you can input a regexp (short for regular expression) that describes the string that will be replaced during the conversion. The neat part is the wizard. Click on the wizard staff and you get a preview of what calibre «sees» during the conversion process. Scroll down to the string you want to remove, select and copy it, paste it into the regexp field on top of the window. If there are variable parts, like page numbers or so, use sets and quantifiers to cover those, and while you’re at it, remember to escape special characters, if there are some. Hit the button labeled Test and calibre highlights the parts it would replace were you to use the regexp. Once you’re satisfied, hit OK and convert. Be careful if your conversion source has tags like this example:

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

(shamelessly ripped out of this thread). You’d have to remove some of the tags as well. In this example, I’d recommend beginning with the tag <b class="calibre2">, now you have to end with the corresponding closing tag (opening tags are <tag>, closing tags are </tag>), which is simply the next </b> in this case. (Refer to a good HTML manual or ask in the forum if you are unclear on this point). The opening tag can be described using <b.*?>, the closing tag using </b>, thus we could remove everything between those tags using <b.*?>.*?</b>. But using this expression would be a bad idea, because it removes everything enclosed by <b>- tags (which, by the way, render the enclosed text in bold print), and it’s a fair bet that we’ll remove portions of the book in this way. Instead, include the beginning of the enclosed string as well, making the regular expression <b.*?>\s*Generated\s+by\s+ABC\s+Amber\s+LIT.*?</b> The \s with quantifiers are included here instead of explicitly using the spaces as seen in the string to catch any variations of the string that might occur. Remember to check what calibre will remove to make sure you don’t remove any portions you want to keep if you test a new expression. If you only check one occurrence, you might miss a mismatch somewhere else in the text. Also note that should you accidentally remove more or fewer tags than you actually wanted to, calibre tries to repair the damaged code after doing the removal.

Aggiunta di libri

Another thing you can use regular expressions for is to extract metadata from filenames. You can find this feature in the «Adding books» part of the settings. There’s a special feature here: You can use field names for metadata fields, for example (?P<title>) would indicate that calibre uses this part of the string as book title. The allowed field names are listed in the windows, together with another nice test field. An example: Say you want to import a whole bunch of files named like Classical Texts: The Divine Comedy by Dante Alighieri.mobi. (Obviously, this is already in your library, since we all love classical italian poetry) or Science Fiction epics: The Foundation Trilogy by Isaac Asimov.epub. This is obviously a naming scheme that calibre won’t extract any meaningful data out of - its standard expression for extracting metadata is (?P<title>.+) - (?P<author>[^_]+). A regular expression that works here would be [a-zA-Z]+: (?P<title>.+) by (?P<author>.+). Please note that, inside the group for the metadata field, you need to use expressions to describe what the field actually matches. And also note that, when using the test field calibre provides, you need to add the file extension to your testing filename, otherwise you won’t get any matches at all, despite using a working expression.

Modifica di gruppo dei metadati

L’ultima parte è l’espressione regolare Cerca e sostituisci nei campi dei metadati. Puoi accedervi selezionando più libri nella libreria e utilizzando la modifica collettiva dei metadati. Fai molta attenzione quando usi quest’ultima funzionalità, poiché può causare cose molto brutte alla tua libreria! Controlla attentamente che le tue espressioni facciano ciò che desideri utilizzando i campi di test e contrassegna solo i libri che desideri veramente modificare! Nella modalità di ricerca delle espressioni regolari, puoi cercare in un campo, sostituire il testo con qualcosa e persino scrivere il risultato in un altro campo. Un esempio pratico: supponiamo che la tua biblioteca contenga i libri della serie Dune di Frank Herbert, dal nome della moda «Dune 1 - Dune», «Dune 2 - Dune Messiah» e così via. Ora vuoi inserire Dune nel campo della serie. Puoi farlo cercando (.*?) \d - .* nel campo del titolo e sostituendolo con \1 nel campo della serie. Vedi cosa ho fatto lì? Questo è un riferimento al primo gruppo con cui stai sostituendo il campo della serie. Ora che hai impostato la serie, devi solo fare un’altra ricerca per .*? - nel campo del titolo e sostituiscilo con "" (una stringa vuota), sempre nel campo del titolo, e i tuoi metadati saranno tutti puliti e ordinati. Non è fantastico? A proposito, invece di sostituire l’intero campo, puoi anche aggiungere o anteporre al campo, quindi, se volevi che il titolo del libro fosse anteposto alle informazioni sulla serie, potresti farlo anche tu. Come avrai sicuramente notato, c’è una casella etichettata Maiuscole e minuscole, quindi non dovrai usare i flag per selezionare il comportamento qui.

Bene, con ciò abbiamo quasi finito questa breve introduzione alle espressioni regolari. Con un po” di fortuna ti avrò mostrato abbastanza per farti almeno partire e permetterti di continuare a imparare per conto tuo - un buon posto dove guardare sarebbe Python documentation for regexps.

Un ultimo avviso, però: nonostante le espressioni regolari siano molto potenti, è anche molto facile sbagliare nel crearle. calibre fornisce ottime funzioni di prova per controllare se le tue espressioni funzionano come ti aspetti. Usale. Cerca di evitare di spararti nel piede. (Cielo, quanto mi piace questa espressione…). Ma anche se dovessi, nonostante i preavvisi, ferirti al piede (o in altre parti anatomiche), prova ad imparare da quanto successo.

Riferimenti rapidi

Riconoscimenti

Grazie per aver contribuito con consigli, correzioni e altro:

  • ldolse

  • kovidgoyal

  • chaley

  • dwanthny

  • kacir

  • Starson17

  • Orpheu

Per più informazioni sulle regex vedi The Python User Manual. In realtà la libreria usata da calibre per le espressioni regolari è regex, che supporta vari utili miglioramenti rispetto alla libreria standard di Python.