A cura di Ugo Santamaria.
Revisione: Claudia Pantanetti.
Consulenza espressioni regolari: Michele De Russi.


Indice


Refusi da OCR e espressioni regolari

Capita, nell’elaborazione OCR della scansione di un testo, che una macchiolina diventi un punto o un accento, che una e diventi o o viceversa, che una l diventi una i o anche 1 (uno). Refusi che a volte sono di difficile individuazione. Uno strumento utilissimo per la ricerca e correzione di questi refusi sono le Espressioni Regolari (in seguito anche regex o espressioni).

Le Espressioni Regolari sono esattamente quello che dice il loro nome, ovvero delle espressioni costruite per elaborare entità che hanno una comune struttura; esse sono applicabili in molti campi. Per allargare il nostro orizzonte di conoscenza, possiamo affidarci anche alla relativa pagina di Wikipedia.

In informatica sono ampiamente utilizzate nella programmazione. Quando clicchiamo il bottoncino con la i per rendere il testo in corsivo, non stiamo facendo altro che applicare una Espressione Regolare. Anche il Cerca/Sostituisci è basato sulle regex e ha il pregio di permettere all’utente di creare/utilizzare anche le proprie espressioni in base alle esigenze contingenti.

Per il loro utilizzo nella elaborazione o correzione dei testi, vi invito a considerare il testo dei libro non più come un insieme di parole, ma come insiemi di sequenze di caratteri che possono essere, o non essere, accomunati fra loro da una stessa struttura costruttiva e/o ambientale.

Vabbe’ costruttiva, ma ambientale?? Prendiamo ad esempio il affermativo e il si pronome: hanno la stessa struttura costruttiva, appena differenziata dall’accento grave nella i del primo. Spesso, in post-OCR, capita che siano confuse fra di loro. Come fare, senza dover passare 2/3 giorni scorrendo si, si, si, si… per verificarne la correttezza? Semplice! Possiamo creare una regex che ci permetta di individuare rapidamente se è presente un qualche refuso da correggere, tipo l’affermazione senza accento o il pronome accentato. Possiamo pensare al contesto – uhm! forse ambiente era esagerato? ma no, pensiamo alla scrittura come a un paesaggio… – come discriminante: l’affermativo per sua natura è seguito quasi nella totalità delle occorrenze da un segno di punteggiatura. Di contro il pronome, che da solo non può stare, è praticamente sempre seguito da uno spazio e poi da qualcos’altro, ma per il momento ci basta lo spazio di separazione, o vuoto. In base a queste osservazioni possiamo pensare a delle regole di ricerca: per l’affermativo potrebbe essere «cerca le combinazioni di caratteri alfabetici s e i uniti, se la i non è accentata, verifica se per caso è seguita da un segno di punteggiatura, che può essere punto fermo, virgola, esclamativo o interrogativo. Se così fosse me lo segnali». Per il pronome la richiesta potrebbe essere «cerca le combinazioni di caratteri alfabetici s e i uniti, se la i è accentata, verifica se è seguita da uno spazio, se affermativo me lo segnali». Però non possiamo esprimerlo a parole, dobbiamo formulare una espressione che traduca la nostra richiesta comprensibile alla applicazione con cui stiamo lavorando ed è qui che una conoscenza, almeno basilare, del linguaggio ci viene utile.

Anche se in questo momento può sembrare ostrogoto, queste sono le espressioni ottenute traducendo le richieste di cui sopra:

\bsi[\.,\?!] e \bsì\s

Nota: La diagonale obliqua rovesciata \ nelle tastiere italiane di solito si trova a sinistra del tasto del numero 1 uno

Strana cosa, nevvero? Beh! È la traduzione letterale nel linguaggio delle Espressioni regolari delle nostre richieste in linguaggio umano.

A prima vista sembrerebbero delle stringhe di testo astruse, ma già apprendendo anche solo alcuni termini del loro linguaggio si scopre la loro potenza e dopo pochissimo tempo rimaniamo stupiti nel scoprirci a pensare «Oh… my… God…! come facevo a vivere senza conoscere la luce!!».

Proviamo a fare una traduzione passo a passo:

\bsi[\.,\?!]

«\b è un confine, è l’inizio della parola, voglio che la seguente sillaba si sia una parola, non devi considerare altre sillabe si che sono precedute da qualsiasi carattere. Inoltre deve essere seguita da un segno di punteggiatura [\.,\?!], fra parentesi quadra metto una scelta di segni che devi prendere in considerazione in questa ricerca». Del perché davanti al punto fermo . e al punto interrogativo ? ci sia una diagonale rovesciata ne parleremo più avanti.

\bsì\s

«\b è un confine, è l’inizio della parola, voglio che la seguente sillaba sia una parola e la ì sia accentata, non devi considerare altre sillabe che sono precedute da qualsiasi carattere, a parole come così ecc., ci penseremo in un altro momento. Inoltre deve essere seguita da uno spazio, rappresentato dal simbolo \s

Facciamo un altro esempio: consideriamo di avere la scansione di Guerra e pace in cui i dialoghi, invece di essere introdotti da un trattino lungo (em bash), abbiano un trattino breve (il segno meno). Fino ad oggi avremmo scorso tutto il testo per trovare ogni occorrenza di e quindi, nel caso si fosse trattato di un inizio dialogo, sostituirla con , diciamo… una settimana di occhi sconquassati?

Con le regex: dopo aver aperto la finestra Ricerca avanzata dal menu “Modifica → Trova e sostituisci…” e aver messo la spunta nell’opzione Epressioni regolari (se non la vediamo, clicchiamo sul triangolino a lato di “Altre opzioni”); scriviamo nel campo Trova:

^-

dove il simbolo ^, che mettiamo davanti a , significa a inizio riga, quindi verranno trovati solo i segni all’inizio di una riga e che quindi sicuramente rappresentano l’inizio di un dialogo e sono da correggere. A questo punto scrivendo nel campo Sostituisci il trattino corretto e premendo il tasto Sostituisci tutto il gioco è fatto e il vostro oculista inizierà a diffondere fake news sulle regex (“uuuhh! Signora mia, si figuri che le usano per propiziare l’avvento del Cthulhu!!!”).

Vademecum Espressioni regolari

Fatto ciò ci accorgiamo che nel nostro Guerra e pace una infinità di questi trattini di inizio dialogo sono appiccicati alla prima parola del dialogo senza il canonico spazio che li separi. …un’altra settimana e gli occhi che sprofondano sempre più nell’abisso di nere occhiaie, sempre più nere…?

Con le regex scriviamo nel campo Trova:

^—(\S)

Nota: S maiuscola.

che significa: a inizio di una riga ^, trova i trattini inizio dialogo , ma solo quelli che sono seguiti da qualsiasi carattere che non sia uno spazio vuoto \S, ovvero che non siano seguiti da uno spazio. Il carattere speciale \S, come approfondiremo più avanti, rappresenta qualsiasi carattere, quindi potrà essere una lettera, un numero, un segno di punteggiatura, proprio qualsiasi cosa, ma non spazio vuoto. Le parentesi tonde () definiscono un gruppo, ovvero un insieme di uno o più caratteri, o anche, come in questo esempio, da un carattere speciale. La loro funzione è passare l’insieme che delimitano ad una variabile.

Nel campo Sostituisci metteremo:

— $1

Nota: fra e $ c’è uno spazio

che significa: metti uno spazio fra il trattino e il carattere che prima gli stava appiccicato$1. Quest’ultima è una variabile.

Possiamo considerare la variabile come un contenitore di dati.

Quindi i dati contenuti fra parentesi tonde, in questo caso (\S), vengono messi nel contenitore che si chiama $1. Ogni volta che utilizziamo $1, stiamo in effetti utilizzando i dati che le parentesi tonde contengono in quel momento. I caratteri speciali fungono da selettori, individuano quello che non sappiamo esattamente cos’è, ma di cui possiamo indicare le caratteristiche. Nell’esempio di (\S) non sappiamo esattamente quale sarà il carattere che verrà trovato, però non vogliamo che sia uno spazio. Ogni volta che (\S) troverà detta situazione passerà il carattere alla variabile, che poi metterà il carattere al suo posto, nel punto in cui avremo deciso di farlo riapparire, sempre nel nostro esempio dopo lo spazio che segue il trattino .

C’è una cosa importantissima da tenere presente: i linguaggi informatici, come quelli reali, a volte hanno forme dialettali. Succede che alcune applicazioni, fra cui LibreOffice, utilizzano il simbolo del dollaro $ per indicare una variabile.

Altre applicazioni utilizzano invece la diagonale obliqua rovesciata \. Per cui nel campo Sostituisci di queste app la nostra espressione diventerà — \1.

Come facciamo a scoprire quale delle due forme di variabile dobbiamo usare? A parte che già sappiamo che LO=$, il modo più semplice con altre applicazioni è andare per tentativi. Inseriamo una delle due versioni, — $1 oppure — \1, nel campo Sostituisci e premiamo il tasto Trova successivo, quindi il tasto Sostituisci, se la sostituzione avverrà correttamente, ovvero ci troveremo con trattino , spazio e prima lettera della prima parola del dialogo è evidente che abbiamo azzeccato alla prima. Nel caso ci apparisse, al posto della prima lettera della prima parola del dialogo, la stessa espressione che abbiamo nel campo Sostituisci, provvederemo a sostituire con l’altro simbolo.

E infine premiamo il tasto Sostituisci tutto. Il vostro oculista cercherà di imbarcarsi nella spedizione di fondazione della prima colonia su Marte

Impariamo qualcosina sulle regex.

Nel web si trovano quintalate di manuali, tutorial ecc. sulle regex. A volte basta chiedere al motore di ricerca cosa si vorrebbe fare e ci si ritrova con una soluzione pronta da applicare.

Ma giusto per distinguere una regex da una frase benaugurale in proto-ostrogoto scritto, per semplificare, in lineare B, vediamo qualche simbolo utile a capire, o meglio a comporre, una regex.


Metacaratteri.

Danno o modificano un significato speciale ai caratteri normali.

  • ^ Indica l’inizio riga. Posto prima di qualsiasi entità indica che ciò che cerchiamo deve trovarsi all’inizio di una riga.Esempio: ^Pluto troverà tutte le occorrenze di Pluto ad inizio riga, anche se fa parte di parole che cominciano per Pluto, tipo Plutocrate.
    Quest’ultimo particolare richiede un po’ di attenzione quando si fa un Cerca/Sostituisci: se voglio che la parola Pluto venga sostituita da Pippo e non do altre indicazioni, succederà che dopo la sostituzione mi ritroverò anche dei simpatici Pippocrati… Più avanti vedremo come delimitare o rendere più esatte le ricerche.

 

  • $ Indica il fine riga. Esempio: pippo$ troverà tutti i pippo a fine riga, anche se sono la parte finale di un’altra parola: per esempio troverà Gianpippo.
    Ma come nell’esempio precedente, se chiediamo di sostituire pippo con pluto, senza altre specifiche di ricerca, ci potremmo trovare anche con un Gianpluto alquanto perplesso di questo repentino cambio di nome.

 

  • | (simbolo pipe o barra verticale) indica OR (oppure), ovvero alternativa. Per esempio: Pippo|Pluto ci troverà alternativamente sia Pippo che Pluto.
    Possiamo utilizzare il pipe anche all’interno di un gruppo, per esempio: quest(a|e|o|i)\b troverà le varie occorrenze di quest seguite alternativamente da una delle vocali inserite fra le parentesi tonde, quindi: questa, queste, questo e questi.

    Nota: L’espressione termina con \b che, come abbiamo già visto, è un confine e in questa posizione definisce la fine della parola. Senza di questo carattere speciale (vedi prossimo capitolo) l’espressione estenderebbe la ricerca a parole più lunghe, tipo questione

  • . (punto) Indica un qualsiasi carattere: lettera, numero, spazio e punteggiatura, proprio tutto. Se scriviamo un punto . nel campo Trova e pigiamo ripetutamente il tasto Trova evidenzierà tutti i caratteri uno per volta.
    Se premiamo il tasto Trova tutto, tutto il testo sarà selezionato. Più avanti scopriremo come delimitare e rendere più utile questo metacarattere.
    Proviamo con il gruppo (.*), ovvero trova 0 o più caratteri di qualsiasi tipo. Ma anche così ci troverebbe tutto il testo e non ha molto senso.
    Proviamo ora a delimitarlo: pippo (.*) pluto troverà tutte le stringhe di testo in cui fra pippo e pluto c’é un qualsiasi testo (.*). Per esempio: pippo segue pluto, oppure pippo vide il suo cane pluto, pippo e pluto ecc.
    Attenzione perché troverà anche «Gianpippo è un plutocrate», e non tralascerà «…pippo, mentre guardava un film de paura, iniziò a piovere. Bla … bla … bla … bla … bla. Il cucciolotto appena uscito dall’uovo era pluto…» Vedremo più avanti come superare questa situazione.

 

  • () (parentesi tonde) servono a racchiudere un gruppo, ovvero una sequenza, di caratteri. Ad esempio (fine) troverà l’insieme esatto di lettere fine sia come parola che come parte di un’altra parola es. confine, finestra. Abbiamo già visto che si possono inserire nelle () anche simboli propri delle regex, come altri metacaratteri o altri simboli esposti in seguito, ma che potrebbero cambiare di significato. I gruppi, nel Trova/Sostituisci definiscono un insieme che verrà assegnato ad una variabile, vedi esempio e spiegazione nel capitolo introduttivo.

    Nota: È importante ricordarsi che se cerchiamo una parola solamente per trovarla non è necessario inserirla fra parentesi tonde, nell’esempio precedente con parentesi o senza viene trovato fine. È necessario inserirla fra le parentesi tonde, come già spiegato nel capitolo introduttivo, quando la si vuole assegnare a una variabile per un successivo utilizzo, come, per esempio, la sostituzione.

  • [] (parentesi quadre) servono a racchiudere una classe di caratteri. es [abc] troverà tutte le a, tutte le b e tutte le c; la classe [a-z] tutte le lettere dell’alfabeto minuscole da a a z, ma potrebbe essere [c-t] da c a t; l’apostrofo dritto e curvo [’']; i numeri [4-7] da 4 a 7. Si possono mescolare: [d-l3-8E-G!%] trova le lettere minuscole da d a l, i numeri da 3 a 7, le maiuscole da E a G, l’esclamativo e il percento.
    Come per le parentesi tonde, anche qui possiamo inserire i simboli propri delle regex, tranne le parentesi tonde intese come gruppo; le () possiamo inserirle come simbolo parentesi ma devono essere precedute da una diagonale rovesciata \, come descritto più avanti. A differenza delle parentesi tonde che determinano una sequenza, gruppo, che verrà considerata nella suo insieme; i caratteri inseriti nella classi, tra parentesi quadre, verranno considerati individualmente.
    Alcuni simboli potrebbero cambiare di significato, ad esempio ^, all’interno delle parentesi quadre esclude dalla ricerca: [^abc] esclude dalla ricerca tutte le a, tutte le b e tutte le c. Un esempio: quest[aei]\b ci troverà questa, queste, questi. Invece quest[^ae]\b escludendo a, e, troverà questi, questo.

    Nota: Anche in questo esempio facciamo terminare l’espressione con \b come confine in modo ché non estenda la ricerca a parole tipo questura. Ma ci troverà quest’ con apostrofo sia dritto che curvo.

    Somiglia all’alternativa con il | in un gruppo? Esatto, in questo caso in cui sono presenti caratteri singoli, si equivalgono, ma non è sempre così.

    Potremmo voler cercare contemporaneamente parole che contengono pip, plu, top. In questo caso siamo costretti ad usare il gruppo di alternative (pip|plu|top) per trovare parole che le contengano (p.es.: pippo, pluto, topolino); se le mettessimo dentro le quadre [pipplutop], a parte che non è necessario ripetere le stesse lettere, verrebbe trovata ognuna di queste lettere in tutte le parole che le contengono.

  • \(diagonale obliqua rovesciata) riporta metacaratteri e quantificatori alla normalità. es. \$ perderà il significato speciale di fine riga e sarà solo il segno del dollaro $; \\ sarà una semplice diagonale obliqua rovesciata.Per esempio: se vogliamo trovare le frasi che terminano con un segno di punteggiatura (punto, interrogativo o esclamativo, limitiamoci a questi tre solo per semplificare l’esempio), scriveremo: (.+)[\.\?!] ovvero: cerca un insieme di 1 o più caratteri (.+) che termina con uno dei tre simboli di punteggiatura fra parentesi quadra.

    Nota: il punto semplice e interrogativo per perdere il loro significato speciale, precedentemente descritto, sono preceduti dalla diagonale obliqua rovesciata \, mentre il punto esclamativo, non avendo nessuna specialità, non ne ha bisogno.

La lista dei simboli da far precedere da \ (in questo caso si chiama escape) perché perdano il loro valore speciale e quindi possano essere inseriti in una espressione con valore normale sono:

^, $, |, ., (, ), [, ], \, *, +, ?, {, }.


Quantificatori.

Vengono posti subito dopo un carattere o dei caratteri (se sono inseriti in una classe es. [abc]) e ne determinano la quantità di ripetizioni o occorrenze. Si possono usare anche per quantificare i gruppi, ma se stiamo agendo su un testo letterario verrà ben poco utilizzato, a meno che non stiamo cercando ratatata: ra(ta){3}.

Nota: per non ripetermi, in tutte seguenti descrizioni scriverò solo occorrenza/e, ma con ciò intendo la frase: occorrenze del carattere o dei caratteri (se sono inseriti in una classe es. [abc]), oppure gruppo che lo precede.

 

  • * (asterisco) 0 o più occorrenze.
    Per esempio: 13*4: cerca un numero che inizia con 1 e finisce con 4 in cui ci siano interposti zero o più occorrenze del numero 3. Troverà: 14, 134, 1334, 13334 ecc.
    Considerando la stessa serie di numeri: con 1(.*)4 li troverebbe tutti 14, 134, 1334, 13334 … , ma troverebbe anche eventuali 154, 16824 ecc.

 

  • + (segno +) 1 o più occorrenze.
    Per esempio: 13+4 e 1(.+)4 a differenza dei due esempi precedenti trovano gli stessi numeri indicati sopra 13+4 => 134, 1334, 13334 ecc.; 1(.+)4 => 134, 1334, 13334_ecc. ma anche _154, 16824 ecc.
    Ma non potranno trovare 14, perché ci deve essere almeno una cifra inframezzata.

 

  • ? (interrogativo) 0 o 1 occorrenza.
    Per esempio: ss?i: trova si oppure ssi.
    Quindi trova: asino, assicurazione ecc.

 

  • {n} esattamente n occorrenze.
    Per esempio: 13{3}4 considerando la serie numerica precedente trova esattamente 13334.
    n{2} trova parole con doppia n (enne): Anna, annotare ecc.
    [aeiou]{2} trova parole che contengono sequenze di 2 vocali: quello, giusto, area ecc.

 

  • {n,} n o più occorrenze.
    Per esempio: 13{2,}4 considerando la serie numerica precedente trova 1334, 13334, 133334 , 1333334, 13333334 ecc.
    [aeiou]{3,} trova parole che contengono sequenze di 3 o più vocali: cioè, cuoio, aiuola, Aiace ecc.

 

  • {n,m} minimo n e max m occorrenze.
    Per esempio: 13{2,4}4 considerando la serie numerica precedente trova esattamente 1334, 13334, 133334 e basta.
    [rst]{2,3} trova parole che contengono le lettere rst in sequenze di 2 o 3, trova: straordinario, asse, irsuto ecc.

Caratteri speciali.

Negli esempi precedenti per indicare un carattere qualsiasi si è utilizzato il metacarattere . punto, che è praticamente un jolly. I caratteri speciali sono più specifici.

Con essi vengono indicate specifiche entità del testo che si vogliono processare; sono sempre preceduti dalla diagonale obliqua rovesciata.

Non si mette lo spazio per separarla dal resto del contesto, a meno che non vogliamo prenderlo in considerazione, lo spazio verrebbe considerato nella ricerca.

  • \b Confine di una porzione di testo: si può inserire prima e/o dopo per definire i limiti di una sequenza di caratteri.
    Posta in precedenza determina esattamente l’inizio del testo da considerare:\bfra troverà parole che cominciano per fra, quindi fra, frappé, frastuono. Ma non troverà p.es.: confraternita o cifra.
    Posta in precedenza e in seguito determina esattamente la sequenza di caratteri: \bfra\b troverà soltanto fra, quindi non frappé o confraternita.
    Posta in seguito fra\b troverà parole che terminano con fra: fra e cifra, ma non frappé, frastuono o confraternita.

 

  • \B qualsiasi posizione che non sia l’inizio o la fine di una sequenza di caratteri.
    Negli esempi precedenti, usando il confine \b non siamo riusciti a trovare la parola confraternita. In questo caso utilizziamo il carattere speciale \B.
    La caratteristica dei caratteri speciali maiuscoli è che sono il contrario del loro rispettivo minuscolo.
    Quindi questo troverà la stringa richiesta in una posizione che non sarà né all’inizio tantomeno alla fine della parola.
    Esempio: \Bfra\B nell’esempio precedente troverà solo confraternita. Ma, se ci fosse, troverebbe anche infradito.

 

  • \d Rappresenta un valore numerico: ovvero indica una qualsiasi cifra da 0 a 9.
    Equivale alla classe di caratteri [0-9].Esempio: \b(\d{10})\b trova esattamente gruppi di 10 cifre (numeri di telefono mobile?).
    Proviamo a reinterpretare un esempio precedente: 1(.+)4 dove avevamo utilizzato genericamente il punto ., che significa qualsiasi carattere (non solo numeri) e +, che significa 1 o più caratteri:, questa regex ci trova i numeri 1354, 17734, 17874 , 1339334, 13318334, ma, se ci fossero, troverebbe anche 1a%4, 1piP@4 ecc.
    Possiamo subito notare che, se vogliamo essere più selettivi e trovare solo sequenze di numeri, il carattere speciale \d ci cade a fagiuolo.
    Infatti 1(\d+)4 ci trova solamente numeri escludendo insiemi che contengono caratteri estranei.Un altro esempio: se volessimo intercettare le date che si trovano in un testo nel formato gg/mm/aaaa dovremmo scrivere: \d\d/\d\d/\d\d\d\d.
    In questa regex possiamo notare che oltre a usare i Quantificatori, si può ripetere un carattere speciale \d per ogni numero che cerchiamo.
    Rivediamo l’esempio precedente di ricerca di numeri telefonici, proposto in due regex diverse e osserviamo le differenze di risultato. In un file odt di prova, scriviamo una sequenza qualsiasi di 10 cifre; nella Ricerca avanzata di LO, campo Trova inseriamo la regex \b(\d{10})\b ovvero «cerca la sequenza isolata dai confini \b di 10 caratteri numerici;» nel campo Sostituisci scriviamo la frase «questo $1 è un numero di telefono»; premiamo il tasto Trova successivo; verrà selezionato il numero di 10 cifre; premiamo il tasto Sostituisci; al posto del numero troveremo la frase che avevamo scritto nel campo Sostituisci e al posto della variabile $1 ci sarà la sequenza di numeri esatta, se non ricordi esattamente cosa è la variabile, la sua descrizione è nel capitolo introduttivo.
    Proviamo ora a inserire nel campo Trova \b(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)\b, invece di un gruppo (\d{10}) abbiamo 10 gruppi (\d) e ogni gruppo sarà assegnato a una variabile che verrà denominata da $1 a $10; scriviamo nel campo Sostituisci la frase «ora abbiamo un numero $5$8$9$3$5 è diverso»; premiamo Trova successivo e verrà selezionata la sequenza di numeri; premiamo il tasto Sostituisci; la sequenza verrà sostituita con la frase, ma i numeri saranno solo 5 e il primo e l’ultimo sono uguali, quindi se la sequenza di numeri trovata è «7890653421» dopo la sostituzione diventerà «64296».

 

  • \D Rappresenta un carattere che non sia un valore numerico.
    Equivale alla classe di caratteri [^0-9], ricordate che tra parentesi quadre il simbolo ^ inserito prima di una sequenza indica l’esclusione della stessa dalla ricerca?Esempio: \b\d*\D+\d*\b trova eventuali numeri che, magari per un refuso, contengono un carattere che non sia una cifra numerica.

    Nota: abbiamo delimitato la sequenza con \b; prima o dopo questo o questi caratteri estranei \D+ ci saranno zero o più numeri \d*. La stessa espressione si potrebbe scrivere \b\d*[^0-9]+\d*\b, ma con \D è più pratico.

  • \w Rappresenta un carattere alfabetico, maiuscolo o minuscolo, incluse le vocali accentate, i numeri da 0 a 9 e il segno _ (underscore).
    Equivale alla classe di caratteri [a-zA-Z0-9_].
    Esempio: \b\w*(fra)\w*\b trova il gruppo fra preceduto e seguito da 0 o più caratteri, praticamente che sia un’unica parola oppure che si trovi all’interno di una parola. quindi troverà: fra, frappé e confraternita.

    Nota: Tutti gli esempi precedenti la descrizione di \b, \d e \w in effetti non evidenziano esattamente le parole, ma solo la sola parte cercata. Prendiamo l’esempio descrittivo del quantificatore ?: nel campo di ricerca avevamo inserito ss?i che trova la parola massimo, ma verrà viene evidenziato solo ssi. Utilizzando le nuove conoscenze scriveremo \b(\w*ss?i\w*)\b, in questo modo viene selezionata la parola intera… personalmente lo trovo più efficace nel caso volessimo sostituire massimo con minimo.

  • \W Rappresenta un carattere che non sia un lettera dell’alfabeto, una cifra o il simbolo _.
    Equivale alla classe di caratteri [^a-zA-Z0-9_].
    Esempio: \b\w*\W+\w*\b cerca delle parole o dei numeri che contengono dei simboli strani che potrebbero essere dei refusi. Trova: abba|no, <asa, cec! ecc. La stessa espressione si potrebbe scrivere `\b\w*[^a-zA-Z0-9_]+\w*\b, ma con \W è più… pratico.

 

  • \s Rappresenta uno Spazio (spazio separatore o vuoto o bianco).
    Esempio: in un testo da OCR vediamo che le parole sillabate accapo non sono state state bene interpretate e troviamo molte occorrenze del tipo: asi- no ecc. la nostra regex per individuarli sarà \b(\w+)(-\s)(\w+)\b cerca parole che contengono un trattino breve e uno spazio (dentro i limiti determinati da \b e \b, cerca una sequenza di uno o più caratteri \w+, seguita da un trattino breve , da uno spazio \s, infine \w+ uno o più caratteri).

    Nota: gli elementi sono stati inseriti fra parentesi tonda, quindi sono dei gruppi, questa scrittura è utile per la sostituzione, che poi sarebbe la correzione del refuso. Inseriamo la regex nel campo Trova. I tre gruppi vengono assegnati a tre variabili: (\w+) a $1, (-\s) a $2 e il secondo (\w+) a $3. Nel campo Sostituisci scriviamo solo le variabili, senza spazi, in modo da ricostruire la parola correttamente $1$3, premendo Trova successivo ci seleziona la prima parola da correggere e con Sostituisci eseguirà la correzione. È corretta? Bene, facciamo un’altra correzione. Tutto bene? Sì? A questo punto possiamo premere Sostituisci tutto.

  • \S Rappresenta tutto tranne spazio. Equivale a [^\s]. Questo lo abbiamo già visto nel capitolo introduttivo.

Le seguenti si chiamano Classi speciali, le ho inserite in questo capitolo perché funzionano come i caratteri speciali finora descritti, anche nelle combinazioni con i quantificatori e i metacaratteri. Nelle descrizioni, nei caratteri alfabetici sono inclusi anche quelli con segni diacritici.

  • [:alnum:] Rappresenta un carattere alfabetico maiuscolo o minuscolo incluse le vocali accentate o numerico. Come\w ma non include il segno _ (underscore). Equivale alla classe di caratteri [a-zA-Z0-9].
    Per esempio: \b[:alnum:]*(fra)[:alnum:]*\b risulta più selettivo del precedente perché non includerebbe nella ricerca un eventuale confraternita_dei_4_limoni per la presenza del __.
    L’esclusione dalla ricerca è [^a-zA-Z0-9].

 

  • [:alpha:] Rappresenta un carattere alfabetico, maiuscolo o minuscolo, incluse le vocali accentate. Come il precedente ma non include i numerici.
    Equivale alla classe di caratteri [a-zA-Z].Per esempio: \b[:alpha:]*(fra)[:alpha:]*limoni\b non includerebbe nella ricerca un eventuale confraternita dei 4 limoni per la presenza del numero 4. Se invece fosse \b[:alpha:]*(fra)[:alnum:]*limoni\b lo prenderebbe in considerazione. L’esclusione dalla ricerca è [^a-zA-Z].

 

  • [:lower:] Rappresenta un carattere alfabetico minuscolo, incluse le vocali accentate. Come il precedente ma solo minuscolo. Equivale alla classe di caratteri [a-z]. L’esclusione dalla ricerca è [^a-z].

 

  • [:upper:] Rappresenta un carattere alfabetico maiuscolo, incluse le vocali accentate. Al contrario del precedente solo maiuscolo. Equivale alla classe di caratteri [A-Z]. L’esclusione dalla ricerca è [^A-Z].

Un esempio pratico.

Abbiamo delle illustrazioni con le didascalie così strutturate: Figura (numero), (testo).

Vogliamo sostituirla in questo modo: Illustrazione nº(numero) – (testo).

Nella finestra della Ricerca avanzata scriviamo:

Nel campo Cerca: ^Figura\s(\d+),\s(.*)$

Traduzione: cerca righe che iniziano ^ con la parola Figura; spazio \s; seguite da un numero ovvero un gruppo () di una o più + cifre \d; virgola ,;di nuovo \s spazio; seguito infine da un testo composto da un gruppo () composto da 0 o più * caratteri . che sarebbe il testo della didascalia; e qui finisce la riga della riga con $.

Nel campo Sostituisci: Illustrazione nº$1 – $2

Traduzione: …e me le ricomponi sostituendo Figura con Illustrazione nº, rimettendo con garbo e a modino la numerazione e testi della didascalia. Ah! dimenticavo… evita di mettere la virgola dopo il numero, separali con un trattino medio .

Nota che nella sostituzione si mette il testo così come sarà senza altre cose strane a parte le variabili $1 e $2, ma abbiamo già visto come funzionano le variabili.

Le variabili vengono aggiornate ogni volta che premendo il tasto Trova successivo si incontra un’occorrenza. In parole povere creando, nella ricerca, dei gruppi con le parentesi tonde – nel nostro caso abbiamo un gruppo numero (\d+) e un gruppo testo (.*) – questi vengono, di volta in volta e per ogni occorrenza, memorizzati in ordine di presentazione e gli viene assegnato “come nome” un numero crescente. Nel nostro caso il numero sarà $1 e il rispettivo testo $2 che inseriranno nel posto loro assegnato i rispettivi valori acquisiti.

In soldoni: quando trova per esempio: “Figura 4, questa è la Gioconda” sostituisce con “Illustrazione nº4 – questa è la Gioconda”.


PepitoCleaner

Il plugin PepitoCleaner, per LO/OO, è certamente una sorta di coltellino svizzero e ci aiuta ad individuare vari refusi da OCR, ma non solo. Vi consiglio di scaricare questa versione di PepitoCleaner, sopratutto per le nuove versioni di LibreOffice:

https://extensions.libreoffice.org/en/extensions/show/5160

Con OpenOffice funziona anche la versione presente nel sito:

https://pepitoweb.altervista.org/pepito_cleaner/index.php?p=manual&i=0

Una volta scaricato, cliccare due volte sul file, si apre LO/OO e si installa da solo. Chiudere e riaprire LO/OO con un odt di prova.

Nel menu Modifica troviamo la voce PepitoCleaner. Cliccandoci sopra si apre una nuova finestrella. Noterete che ha già parecchi strumenti per la pulizia dei testi.

Il manuale d’uso è semplice da comprendere e si trova qui:

https://pepitoweb.altervista.org/pepito_cleaner/index.php?p=manual&i=1

Nella figura si può vedere il risultato della ricerca premendo la prima icona in alto a sinistra (la lente d’ingrandimento). Si può notare come vengono intercettati refusi che spesso sono ’invisibili’.

Vademecum Espressioni regolari

Premendo sulla seconda icona cerca stringhe che contengono un trattino. Spesso sono parole composte, quindi falsi positivi, ma sicuramente è utile per intercettare le parole che hanno fisicamente un trattino di accapo.

Vediamo nella figura seguente la parola “ca-talogo” che è sicuramente un refuso. Le tre icone in basso a sinistra ci permettono di correggere a seconda delle situazioni: per esempio eliminando il trattino, oppure sostituendolo con uno spazio.

Vademecum Espressioni regolari

Con la terza icona (triangolo con punto esclamativo) cerca possibili errori.

Con altri volontari è qui che ci stiamo concentrando maggiormente nell’inserire delle regex funzionali alle nostre correzioni.

Sotto le icone c’é la finestra del menu. Cliccandoci sopra possiamo scorrere l’elenco di regex. Possiamo scegliere Tutti i possibili errori che eseguirà tutte le regex in una volta dandoci una unica lista di possibili refusi; oppure possiamo procedere selettivamente, scegliendo la regex che al momento può tornarci più utile.

Nella figura sottostante è stata scelta una regex, per un refuso abbastanza frequente, per cercare eventuali articoli IL con la elle minuscola che ritroviamo come i maiuscola.

Vademecum Espressioni regolari

Cliccando su una voce del risultato in basso si apre una finestrella che ci permette di di correggere il refuso, cliccando sul segno di spunta viene applicata l’azione.

Ci sono altre funzioni interessanti, come quella che ci permette di individuare ad esempio le divisioni del libro, come capitoli o parti ecc.; oppure la gestione degli stili applicati nel testo, ad esempio trovare stili estranei che possiamo facilmente sostituire con i nostri prescelti.

Copiare le nuove regole è semplicissimo, rimando al manuale per fruire delle figure illustrative:

https://pepitoweb.altervista.org/pepito_cleaner/index.php?p=manual&i=16

si procede nella scheda attivabile cliccando l’icona a*?, dal menu selezionate Lista RegEx Possibili Errori, si tratta di selezionare e copiare il testo contenuto nei file, i cui aggiornamenti sono pubblicati nel Forum di Manuzio.

Una volta copiato in memoria (control+c; oppure Copia; cmd+c per Mac) si preme il bottoncino con la cartella (vedi figura nel manuale), si aprirà un’altra finestra che conterrà il testo già copiato (non c’è bisogno di copiarlo dentro), confermare.

Se per caso si dovesse aprire una finestra dove vi si chiede se sovrascrivere o creare una nuova chiave, scegliete la seconda, confermate. Nel caso si creino doppioni verificare quale funziona meglio e cancellare l’altro.

Finita l’operazione, nell’elenco delle regole ci saranno varie voci nuove, per provarle andate nella scheda “Ricerca possibili errori” (il triangolo di allerta), dal menu si può scegliere la prima voce che è complessiva o una delle seguenti che sono selettive, ci saranno anche le nuove regole.


Alcune regex

Vediamo qualche altro esempio di regex, per cercare di comprendere il loro funzionamento. Provatele nella Ricerca avanzata di LO/OO, ricordandovi di mettere la spunta su “Espressioni regolari” e toglierla da “Maiuscole/minuscole”.

Vademecum Espressioni regolari


ì’ e 1’ al posto di l’ (elle), trova anche a fine parola:
\b\w*(1|ì|i|I|Ì)[’']\w+\b

Spesso capita di ritrovarsi con il refuso di una elle minuscola che diventa una I (i maiuscola) o il numero 1 (uno).

Descrizione: in un confine stabilito dai \b estremi; cerca alternativamente (è la sequenza compresa tra parentesi tonde) il numero 1 (uno), | oppure una i con o senza accento, maiuscola o minuscola; seguita da (fra parentesi quadre) un apostrofo (apice o curvo); può essere preceduto da 0 o più caratteri \w*: può essere seguito da uno o più caratteri \w+.

Le combinazioni che ci troverà questa espressione potranno essere: 1’opera, deli’asino ecc.

Nota: indirettamente ci troverebbe altri tipi di refusi, come p.es.: i’clica al posto di elica, che è poi un altro refuso da OCR abbastanza frequente.

Altra Nota: fra parentesi quadre abbiamo l’apostrofo sia dritto che curvo perché potremmo trovare sia l’uno che l’altro. Da ciò risulta evidente, spero, che ciò che mettiamo fra parentesi quadre indica quello che ci aspettiamo di trovare: insieme, in parte o alternativamente. In questo caso è sicuramente alternativamente. Avremmo anche potuto esprimerlo con (’|’)che indica ugualmente una alternativa, ed è come abbiamo fatto per le i e 1. Spero che risulti chiaro che l’alternativa espressa fra parentesi tonde delle i e 1, essendo in questo caso costituita da caratteri singoli, avremmo potuta scriverla [1ìiIÌ].


vocale accentata con apice:
\b\w*[aeiou][’']\b

Un altro errore che troviamo spesso in elaborazioni datate, ma non solo, sono le vocali accentate con l’apice o con l’apostrofo .

Descrizione: cerca parole – in questo caso i confini \b determinano esattamente una parola – composte da 0 o più caratteri \w* e che termina con una vocale seguita da un apice o un apostrofo, il quale presumibilmente è un accento.

Notare che per logica avremmo dovuto mettere \w+ (1 o più caratteri), si presume infatti che una vocale accentata stia sempre alla fine di una parola preceduta vari caratteri. Mettere \w* ( (zero o più caratteri) non è altro che un escamotage che ci permette di trovare anche vocali isolate, che nello specifico non possono che essere e’, ovvero voce verbale con accento sbagliato.

E così son due piccioni con una fava…

Nota: Avremmo potuto scrivere la regex come alternativa di vocali \b\w*(a|e|i|o|u)[’']\b, essendo una scelta fra caratteri singoli è più semplice la prima, ma se ci dovesse servire per inviarla a una variabile questa seconda è la giusta.


concordanze sbagliate dopo l’articolo il:
\bil\s\w+i\b

Questa regola cerca le concordanze sbagliate fra l’articolo il e la parola seguente che a ragion di logica non può terminare con i.
Descrizione: cerca, nei limiti indicati dai confini \b, l’articolo il, \s spazio, uno o più caratteri \w+ seguiti dalla vocale i.


parole che terminano con ché senza accento o con accento grave:

\b((a(ffin|nzi|llor))|(ben)|(chec)|(d(ac|opodi))|((fin)?(tanto)?)|(fuor)|(g(ran|iac))|(non)|(mac)|(p(er|ur|oi))|(senon)|(tal))ch[eèé]\b

Sembra complicata? No, è solo lunghetta e suscettibile ad ulteriori aggiunte, suggeritemi le parole che mancano, grazie.

Come dice il titolo trova le parole che finiscono in ché, ma che spesso troviamo con accento grave o senza accento.

Credo che possiate già individuarne la struttura, non farò una descrizione dettagliata, ma indico una chiave di lettura.

Che sia una parola lo vediamo definito da i \b agli estremi. Come terminano tutte in che/chè/ché è chiaro? A proposito perché anche il ché con l’accento corretto? Questo lo spiego dopo.

Quindi quella che vediamo fra le parentesi tonde, primo livello di parentesi, è l’inizio della parola a cui poi si aggiunge il ch[eèé].

Vediamo che i gruppi – quelli fra parentesi tonda, secondo livello di parentesi, – sono separati dal simbolo |, che abbiamo visto significa oppure.

Ora prendiamo per esempio il gruppo (a(ffin|nzi|llor)) … si intende che sta per affin…, anzi…, allor…? Abbiamo visto, quindi, che i gruppi di alternative possono essere nidificati, ovvero l’espressione che abbiamo preso ad esempio è già un’alternativa ad altri inizi di parola che terminano in ché, come per esempio (ben) o (non), ma è formata da una a seguita da un’alternanza di sequenze di lettere con cui può formare, aggiungendo infine ché, tre parole distinte aventi qualche lettera in comune.

Nota: la regex dell’esempio avremmo potuta scriverla anche a(ffin|nzi|llor) senza le parentesi tonde, ma già sappiamo – lo ricordiamo? – che un gruppo fra parentesi tonda è utile per essere assegnato a una variabile per una eventuale sostituzione o correzione.

Si sarebbe potuto scrivere parola per parola, ma così… ci siamo allenati a usare le regex :)

Perché ho inserito nella ricerca anche la é correttamente accentata?

Capita di trovare dei testi in cui, per qualche ragione che non è dato sapere, la stessa parola è accentata a volte con l’acuto e altre con il grave. Fra le regole di impaginazione del gruppo Manuzio è previsto che se si presenta detta situazione, si adeguano gli accenti all’occorrenza più numerosa.

Questa regex è stata pensata per essere applicata in PepitoCleaner, questo perché nella risposta ci indica la quantità di occorrenze delle due possibilità di accento. Da lì stesso possiamo selezionare l’opzione che ci interessa correggere, quindi possiamo agire direttamente della finestrella che si apre in basso.

Vademecum Espressioni regolari

Altrimenti, l’alternativa senza regex, dal campo di ricerca dovremmo inserire una parola per volta e poi cerca conta, cerca conta, cerca conta… o conoscete un metodo più rapido?


sostituisci le virgolette dritte con le curve:
nel campo “Cerca”: "(.*?)"
nel campo “Sostituisci”: “$1”

Quest’ultima regex è molto utile quando per esempio si vogliono sostituire una struttura comune con un’altra impostata con una differente struttura comune, l’abbiamo già vista all’opera in alcuni esempi precedenti. In questo caso specifico cerchiamo stringhe di testo racchiuse fra doppie virgolette dritte per poi sostituirle con le più graziose doppie virgolette curve.

Abbiamo già visto precedentemente l’utilizzo di questa struttura di ricerca e della variabile $1, ma questo esempio mi serve per dare un altro avvertimento, da tenere sempre bene a mente, sullo spirito burlone e sottilmente maligno delle espressioni regolari: se ci trovano per un attimo distratti, siamo fritti!

Dovete anche sapere che i quantificatori nelle regex sono normalmente golosi, se non vengono controllati cercano di inglobare più testo possibile, arrivando fino all’ultima occorrenza, ad esso relativa, presente nel capoverso (almeno così funziona con LO, con altre applicazioni arriva fino all’ultima del testo).

Vi invito a fare una prova: prendete un testo con varie citazioni virgolettate nello stesso paragrafo, ora non importa quali virgolette, ma nella regex mettete le stesse, e provate senza il punto interrogativo, così:

"(.*)"

premete su Trova successivo e noterete che il testo selezionato inizia dalla prima virgoletta aperta trovata e arriva fino all’ultima chiusa capoverso, facendosi un baffo di tutte le virgolette di chiusura incontrate prima. Che dire, ingorde vero?

Per renderle pigre, cioè obbligarle a fermarsi alla prima occorrenza di virgolette di chiusura, occorre mettere dopo il segno quantificatore, in questo caso *, un altro quantificatore, ovvero il punto interrogativo ? e così gli diamo il limite:

"(.*?)"

Insomma, impara la buona educazione e si ferma alla prima occorrenza di chiusura delle virgolette.

Nota: quindi ricordiamo che quando prepariamo una regex contenente un quantificatore e, provandola, notiamo che deborda rispetto a quello che avevamo previsto selezionasse, dopo detto quantificatore aggiungiamo il quantificatore ? – ricordiamo che ? significa «ripeti zero o una volta»? – e la selezione non andrà più oltre il limite della prima occorrenza. Risulterà ovvio che lo useremo per limitare anche gli altri quantificatori: +?, ??.

Chiaramente il fatto che siano golose non è di per sé una cosa negativa, può essere utile in altre situazioni. Quindi, quando volete applicare questa struttura di ricerca valutate di volta in volta quel che vi occorre, magari provando su una copia di prova, prima di dare il fatidico ed anelato Sostituisci tutto.

Le definizioni golose o ingorde e pigre sono proprio quelle ufficiali tradotte dall’inglese, non mi sono inventato nulla.


Altre Espressioni regolari, con relativa descrizione, vengono discusse dai volontari dei gruppi Manuzio e Griffo e poi pubblicate in questa pagina, pronte per essere usate.


Ma… l’oculista? Ovvero: occhio alla penna!

Ora lo posso dire: l’oculista, oramai su Marte, non aveva tutti i torti, non dico che le regex si possano utilizzare per propiziare l’avvento di Cthulhu in una notte di mezza estate, ma… sì, hanno davvero un lato oscuro, a volte diabolico.

Giusto per capire: all’inizio ho citato la regex .*: se la inseriamo nel campo Trova, mentre nel campo Sostituisci scriviamo pippo, premendo sostituisci il nostro “kiloso” Guerra e pace avrà poi come unico testo la parola pippo.

Di scherzetti terribili le regex ne possono fare tanti, quindi MASSIMA ATTENZIONE. Quel che segue è quasi tutto basato su dolorose esperienze personali, … altro che l’orrore che genera Cthulhu nelle notti di luna nera!

Ecco alcune avvertenze che saranno da scolpire a caratteri cubitali nel bordo della tastiera:

PRIMA DI IMPIEGARE QUALSIASI REGEX:

  1. SALVATE IL LAVORO IN UN COPIA.
  2. PREPARATE LA MODIFICA, MEDITANDOLA CON CURA.
  3. PROVATE PER BENE CHE FUNZIONI SOSTITUENDO UNA OCCORRENZA PER VOLTA PRIMA DI PIGIARE “SOSTITUISCI TUTTO”.
  4. CONTROLLATE CHE SIA ANDATA A BUON FINE.
  5. SOLO IN CASO AFFERMATIVO RIFATE IL BACKUP E ANDATE AVANTI, SEMPRE CON MOOOOLTA CAUTELA.

Cosicché, in caso di qualsivoglia disastro, si possa riprendere dal punto precedente, senza sfoderare un ricco vocabolario di turpiloquio verso le regex e, spero, ancor meno contro la mia persona che vi istiga ad usarle.

NON cancellate le copie di backup fino a quando non siete strasicurissimamentecertissimi di aver terminato completamente il lavoro, ed anche allora aspettate un altro po’.

Dopo aver applicato una regex, controllato, salvato ecc., PRIMA di fare o pensare qualsiasi altra cosa RIPULITE da ogni carattere i campi Trova e Sostituisci, meglio andare a verificare con il cursore perché gli spazi non si vedono, e togliete la spunta dalla opzione Espressioni regolari, basta un non nulla per premere inavvertitamente il tasto Sostituisci tutto e rendersi conto solo a pagina 5724 che è successo qualcosa di strano, ma non riuscire a ricordare quandooo? doveee? perchéee? insomma tutte quelle domande che ci facciamo prima di aprire a capocciate una nuova finestra nel muro.


Concludo.

Ora che sappiamo cose che il 99% della popolazione italiana ignora, non montiamoci la testa facendo ricerche metafisiche del tipo «La risposta alla vita, all’universo e tutto quanto», anche perché la risposta è nota ed è 42 e se non ne eravate al corrente goooglate la domanda.

L’argomento Espressioni regolari non termina con questo minimo vademecum, ho trattato solo alcuni elementi basilari, ci sarebbe tanto altro da dire, ma ancora non lo conosco. È comunque sufficiente per soddisfare la necessità prefissata all’inizio: l’oculista è migrato!

E vi assicuro che l’effetto collaterale di correggere al volo tutti gli 1 camuffati da elle minuscola da una soddisfazione indicibile….