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 classi di caratteri da trovare: per definirne uno, metti tutti i caratteri che vuoi avere nella classe dentro parentesi quadre. Quindi, ad esempio, la classe [abc] troverebbe sia il carattere «a», sia «b» sia «c». Le classi troveranno sempre solamente uno dei caratteri della classe. Esse «riconoscono» gli intervalli, ovvero, se volessi trovare tutti i caratteri minuscoli dovresti usare la classe [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 le classi possiamo trovare un carattere tra molti inclusi. Ma puoi anche ripetere un carattere o una classe, 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, una classe 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 le classi: 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 le classi più utili?

Sapevo che l’avresti chiesto. Alcune utili classi 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

Le classi di maiuscole e minuscole possono corrispondere a entrambe se è abilitata l’impostazione che non distingue tra maiuscole e minuscole. Tali impostazioni si trovano, ad esempio, in Preferenze->Ricerca in calibre stesso e nel pannello di ricerca del Lettore e-book di calibre, così come nello strumento Modifica libro.

Come nota conclusiva sulle classi, puoi anche definire una classe composta di tutti i caratteri tranne quelli nella classe. Puoi far ciò includendo il carattere "^" come primo carattere della classe. In questo modo, [^a] troverebbe ogni carattere eccetto «a». Questa operazione è detta «integrare la classe». 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 la classe di caratteri utilizzata 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 (?i flag vanno qui) dove, ovviamente, sostituirai «i flag vanno qui» con i flag specifici che desideri. Per ignorare maiuscole e minuscole, il flag è i, quindi includi (?i) nella tua espressione. In questo modo, (?i)test troverà una corrispondenza con «Test», «tEst», «TEst» e qualsiasi altra variazione di maiuscole e minuscole a cui potresti pensare.

Un altro utile flag fa in modo che a un punto corrispondano tutti i caratteri incluso il carattere newline, il flag s. Se vuoi usare più di un flag in un’espressione, inseriscile semplicemente nella stessa espressione: (?is) ignorerà maiuscole e minuscole e farà corrispondere il punto a tutti i caratteri. Non importa quale flag specifichi per prima, (?si) darà gli stessi risultati.

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

Conversioni

Iniziamo dalle impostazioni di conversione, che hanno potenzialità interessanti. Nella scheda Cerca & sostituisci, puoi inserire una regex (abbreviazione di «regular expression») che descrive la stringa da sostituire durante la conversione. La parte davvero interessante è la procedura guidata. Clicca sulla bacchetta magica per mostrare un’anteprima di ciò che calibre «vede» durante il processo di conversione. Scorri verso il basso fino alla stringa che vuoi rimuovere, selezionala e copiala, poi incollala nel campo regex nella parte alta della finestra. Se ci sono parti variabili come numeri di pagina o altro, usa le classi e i quantificatori per catturarli, e già che ci sei, ricordati di usare la sequenza di escape per i caratteri speciali, se ce ne sono. Premi il pulsante Prova e calibre evidenzierà le parti che sostiruirebbe se usassi quella regex. Quando sei soddisfatto, premi OK per convertire. Fai attenzione se la sorgente per la conversione contiene tag come quelli di questo esempio:

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

(vergognosamente copiata da questa discussione). Ci sarebbero da rimuovere anche alcuni dei tag. In questo esempio, ti consiglio di iniziare dal tag <b class="calibre2">, dopodiché devi rimuovere il tag di chiusura corrispondente (i tag di apertura sono <tag>, quelli di chiusura sono </tag>), che in questo caso è semplicemente il </b> successivo (se questo punto non ti è chiaro, fai riferimento a un buon manuale di HTML o chiedi aiuto sul forum). Il tag di apertura può essere descritto da <b.*?>, quello di chiusura da </b>, perciò potremmo rimuovere tutto ciò che si trova tra i due tag con <b.*?>.*?</b>. Usare questa espressione però non sarebbe una buona idea, perché rimuoverebbe qualunque testo racchiuso da tag <b> (che, come nota, applica il grassetto al testo racchiuso) ed è più che probabile che parti del libro verrebbero rimosse come conseguenza. Conviene invece includere anche la parte iniziale della stringa racchiusa, usando l’espressione regolare <b.*?>\s*Generated\s+by\s+ABC\s+Amber\s+LIT.*?</b> Invece di digitare esplicitamente gli spazi della stringa, viene usato `s` con i quantificatori, per catturare ogni possibile variazione della stringa. Se provi una nuova espressione ricorda di controllare tutte le rimozioni che calibre applicherà, per essere sicuro di non rimuovere parti che vuoi conservare. Se ne controlli solamente una, potresti perderti una corrispondenza non voluta da un’altra parte nel testo. Ricorda anche che se dovessi rimuovere più (o meno) tag di quelli che volevi, calibre proverà a riparare il codice danneggiato dopo la rimozione.

Aggiunta di libri

Un altro caso in cui puoi usare le espressioni regolari è per l’estrazione di metadati dai nomi dei file. Puoi trovare questa funzionalità nella sezione «Aggiunta libri» delle impostazioni. Qui c’è una funzione speciale: puoiu usare i nomi dei campi per i campi dei metadati, per esempio (?P<title>) indica a calibre di usare questa parte della stringa come titolo del libro. I nomi di campo permessi sono elencati nella finestra, insieme a un altro comodo campo di prova. Un esempio: immagina di voler importare una gran quantità di libri con nomi del tipo Grandi Classici: La Divina Commedia di Dante Alighieri.mobi. (naturalmente sarà già nella tua biblioteca, chi non ama la poesia classica italiana?) oppure Epopee della Fantascienza: Trilogia della Fondazione di Isaac Asimov.epub. Questi ovviamente sono nomi di file da cui calibre non riuscirà a estrarre niente di utile - l’espressione predefinita usata per estrarre i metadati è (?P<title>.+) - (?P<author>[^_]+). Un’espressione regolare che sarebbe utile in questo caso è [a-zA-Z]+: (?P<title>.+) di (?P<author>.+). Tieni presente che dentro al gruppo per il campo dei metadati devi usare espressioni che descrivano cosa trovare per quel campo. E ricorda anche che quando usi il campo di prova fornito da calibre devi aggiungere al nome del file di prova la sua estensione, altrimenti non otterrai alcuna corrispondenza, anche se usi un’espressione adatta.

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.