RegEx 2: Il trattamento testi con le espressioni regolari
Di Mario Canton
()
Info su questo ebook
Si spera di aver ottenuto una maggiore semplicità di esposizione che renda meno ostico l'avvicinamento alle regex.
In questa seconda edizione si sono anche prese in esame le varianti (flavours) più diffuse di motori per espressioni regolari, come quelle di editor (EditPad Pro e Lite, Emacs, MS Word, Notepad++, Libre/Apache/Open Office Writer, Vim), fogli di calcolo (Google Documenti – Fogli), database (MySQL, Oracle, PostgreSQL, SQLite), app e shell (Apache HTTPd, Awk, Find, Grep, Nginx, PowerGrep, PowerShell, Sed, ShellScript o Bash), linguaggi di programmazion [C, C++, Delphi, HTML5, Java (con Groovy), JavaScript/ActionScript (con XRegExp), .NET, Perl, PHP, Python, R, Ruby, Tcl, VBScript (Visual Basic), XML, XQuery e XPath, Xojo o Real Basic], librerie (vxRegex, POSIX Base, GNU, Reggex, PCRE) e tester (text2regex, VisualRegExp, Regex Coach, RegexPal, Regex101).
Si presume che, anche se l'applicazione che si utilizza non è esplicitamente menzionata, probabilmente usi una variante che viene trattata sotto un'altra denominazione. In genere la maggior parte delle applicazioni sviluppate usano una delle varianti che sono state prese in esame, in quanto la maggior parte delle applicazioni vengono sviluppate utilizzando un ambiente di programmazione o delle librerie di espressioni regolari tra quelle considerate in questo ebook.
Si è infine integrato la parte riepilogativa con ulteriori tabulati e quadri sinottici dei comandi e degli operatori (anche relativi alle diverse varianti) e aggiunto una breve appendice tecnica sugli automi finiti, l'algebra e i linguaggi regolari, che stanno alla base della «logica» delle regex.
È stata riorganizzata la bibliografia per argomenti (trattazioni generali, Perl e regex, applicazioni specifiche, guide online e testi sulle correlazioni con gli automi a stati finiti).
Leggi altro di Mario Canton
Correlato a RegEx 2
Titoli di questa serie (3)
RegEx per autori, scrittori e redattori. Guida operativa all'utilizzo delle espressioni regolari nel trattamento di testi digitali. Valutazione: 0 su 5 stelle0 valutazioniRegEx 2: Il trattamento testi con le espressioni regolari Valutazione: 0 su 5 stelle0 valutazioniRegEx3: L'uso delle espressioni regolari nelle applicazioni e nei linguaggi Valutazione: 1 su 5 stelle1/5
Ebook correlati
Php le basi: per principianti Valutazione: 0 su 5 stelle0 valutazioniPHP Valutazione: 0 su 5 stelle0 valutazioniC# Programmazione per principianti Valutazione: 0 su 5 stelle0 valutazioniVba Se vi Piace 01 Valutazione: 0 su 5 stelle0 valutazioniProgrammatore in 3 Giorni: Guida Ipersintetica per Principianti Valutazione: 0 su 5 stelle0 valutazioniPHP: Sviluppo Web Lato Server: Programmazione Web, #2 Valutazione: 0 su 5 stelle0 valutazioniPython: La Guida Per Imparare a Programmare. Include Esercizi di Programmazione.: Programmazione per Principianti, #1 Valutazione: 0 su 5 stelle0 valutazioniProgrammare In Java Valutazione: 0 su 5 stelle0 valutazioniCoding in R per l'analisi dati - da principiante a esperto Valutazione: 0 su 5 stelle0 valutazioniLinguaggi Formali e Compilazione Valutazione: 0 su 5 stelle0 valutazioniRegEx3: L'uso delle espressioni regolari nelle applicazioni e nei linguaggi Valutazione: 1 su 5 stelle1/5Creare bot telegram - guida italiana Valutazione: 1 su 5 stelle1/5RegEx per autori, scrittori e redattori. Guida operativa all'utilizzo delle espressioni regolari nel trattamento di testi digitali. Valutazione: 0 su 5 stelle0 valutazioniLinux Facile Valutazione: 0 su 5 stelle0 valutazioniProgrammazione di Expert Advisor Per Principianti: Strategie Forex MT4 con Profitto Massimo Valutazione: 0 su 5 stelle0 valutazioniJavascript: Un Manuale Per Imparare La Programmazione In Javascript Valutazione: 0 su 5 stelle0 valutazioniLa programmazione orientata agli oggetti Valutazione: 0 su 5 stelle0 valutazioniSQL Server Funzioni e tutorial 50 esempi Valutazione: 0 su 5 stelle0 valutazioniProgetti Arduino con Tinkercad | Parte 2: Progettazione di progetti elettronici avanzati basati su Arduino con Tinkercad Valutazione: 0 su 5 stelle0 valutazioniProgrammazione in JavaScript Valutazione: 0 su 5 stelle0 valutazioniElaborazione del linguaggio naturale con Python Valutazione: 0 su 5 stelle0 valutazioniIntelligenza artificiale: classificare la corrispondenza Valutazione: 0 su 5 stelle0 valutazioniProgrammazione di Expert Advisor Per Principianti Valutazione: 0 su 5 stelle0 valutazioniSharePoint Guida Pratica: Siti e App con Office 365 e SharePoint Valutazione: 0 su 5 stelle0 valutazioniPROGRAMMARE IN C# 10 - Tecniche di base Valutazione: 0 su 5 stelle0 valutazioni
Recensioni su RegEx 2
0 valutazioni0 recensioni
Anteprima del libro
RegEx 2 - Mario Canton
RegEx 2
Il trattamento testi
con le espressioni
regolari
di Mario Canton
Edizione 2018
PROPRIETÀ INTELLETTUALE LETTERARIA RISERVATA
© Copyright 2018 by Mario Canton
2ª edizione digitale – 2018
––=ooOoo=––
Se si volesse condividere questo ebook con altre persone, si chiede cortesemente di scaricare una copia a pagamento per ciascuna delle persone a cui si vuole assegnarlo in uso.
Se si sta leggendo questo ebook e non lo si è acquistato, qualora sia di gradimento, si chiede cortesemente di acquistarne una copia a pagamento per sostenere la continuità e il miglioramento dell'attività così da consentire l'opportunità di poter offrire ulteriori titoli con una qualità sempre crescente.
Si ringrazia per il sostegno e il rispetto per il lavoro dell'autore, del redattore e dell'editore di questa pubblicazione.
––=ooOoo=––
Note
Se il lettore fosse gentilmente disponibile a collaborare per il miglioramento dell'opera, è possibile segnalare qualsiasi refuso e/o malfunzionamento operativo incontrato nella lettura dell'ebook inviando una e-mail all'indirizzo dell'autore (mario.canton@tiscali.it).
L'autore si impegna ad apportare nel più breve tempo possibile le correzioni ritenute opportune e/o necessarie.
Grazie sin d'ora per l'eventuale collaborazione.
––=ooOoo=––
Avvertenze
È stato fatto ogni sforzo per realizzare questo libro nella forma più completa e accurata possibile, ma non c'è alcuna garanzia implicita sulla perfetta accuratezza del contenuto.
I linguaggi e gli strumenti di sviluppo vengono aggiornati molto rapidamente, perciò i contenuti di questo ebook sono fedeli allo «stato dell'arte» alla data di pubblicazione, come pure il livello di aggiornamento dei dati indicati.
Le informazioni sono riportate «così come sono».
Pertanto, l'autore non è responsabile di eventuali danni derivanti dall'applicazione delle informazioni contenute in questa pubblicazione.
Sintesi, citazioni o estratti di parti di altre pubblicazioni e la loro evidenziazione sono effettuate ai sensi dell'art. 70 della legge 22 aprile 1941, n. 633, in quanto utilizzate per fini di ricerca o discussione, nei limiti giustificati da tale scopo, e non intendono mettersi in concorrenza con l'utilizzo economico delle opere riprodotte, citate o sintetizzate.
––=ooOoo=––
Alla memoria
del prof. Stephen Cole Kleene,
(* 5.1.1909 † 25.1.1994)
con somma gratitudine ...
... per tutta la fatica evitata,
per tutta la precisione ottenuta
e per tutto il tempo della mia vita
risparmiato e dedicato ad altro.
Indice
Prefazione
Prefazione alla seconda edizione
Ringraziamenti
Due parole sulle origini
Le implementazioni
Gli automi finiti
L'utilizzo delle espressioni regolari
Terminologia
Differenti «motori» delle RegEx
Un prima prova con le RegEx
Introduzione
Le espressioni regolari
Metacaratteri
Rappresentativi
Quantificatori
Ancoraggi
Altri
Metacaratteri di tipo rappresentativo
Punto «.»
Lista «[...]»
Intervallo nelle liste
Padroneggiare i caratteri accentati (con POSIX)
Lista negata «[^...]»
Metacaratteri di tipo quantificatore
Opzionale (punto interrogativo) «?»
Come leggere una espressione regolare
Asterisco «*»
Introduzione del concetto di «golosità» (avidità, greediness)
Introduzione del concetto di «jolly» (.*)
Più «+»
Graffe (parentesi) «{n,m}»
Metacaratteri di tipo ancoraggio
Circonflesso (accento) «^»
Dollaro (segno del) «$»
Bordo «\b»
Altri metacaratteri
Escape «\»
O (alternativa) «|»
Gruppo «(...)»
Retrovisore «\1 ... \9»
Ulteriori dettagli
Sui Metacaratteri
Tempi e applicazioni diverse, distorsione di metacaratteri
Quantificatori golosi
Quantificatori non-golosi
Metacaratteri tipo barra-lettera
Metacaratteri moderni
Precedenza tra metacaratteri
Gli operatori fondamentali per la ricerca Trattazione sistematica
Un ricerca base
Il punto
Le cifre
Gli spazi
Gli insiemi di caratteri (set)
Le sequenze di caratteri [ - ]
Tutti i caratteri «tranne» [^ ]
Le parole
Ancore
I caratteri di una parola \w
Non-codici
I confini di una riga
I confini di tutto un testo
I quantificatori Uno o più caratteri: +
I quantificatori Zero o più caratteri: *
I quantificatori Zero o uno: ? (eventualità)
I quantificatori Il numero di ripetizioni: { }
Quantificatori avidi o pigri (greedy o lazy)
I raggruppamenti: Il riferimento all'indietro (backreference)
I raggruppamenti: I gruppi di espressioni (…)
I raggruppamenti: Il gruppo nominato (?P< > )
I raggruppamenti: Il gruppo passivo (?: )
I raggruppamenti: L'espressione condizionale (?: )
I raggruppamenti: L'alternativa: |
La codifica: Unicode
La codifica: ASCII
Guardarsi intorno (lookaround): Guarda avanti se diverso (?! )
Guardarsi intorno (lookaround): Guarda avanti se uguale (?= )
Guardarsi intorno (lookaround): Guarda indietro (?
Caratteri particolari: bell \a (alarm)
Caratteri particolari: Carattere di controllo \c
Caratteri particolari: Carattere di escape \e
Caratteri particolari: Carattere form feed \f
Caratteri particolari: Caratteri a-capo e ritorno carrello \n e \r
Caratteri particolari: Caratteri di tabulazione \v e \t
Commento (?# )
I modificatori: Maiuscole e minuscole uguali /i
I modificatori: Modalità singola riga /s
I modificatori: Modalità multi-riga /m
Princìpi
Non complicare
Usare il circonflesso
Evitare la lista negata
Evitare la wildcard
Essere specifici
Niente follia ma razionalità
Operazioni
Problemi con maiuscole e minuscole
Espressioni regolari pre-processate e «crude»
Multilinearità
Accentazione
Errori e incovenienti
Backtracking quantificatori possessivi e gruppi atomici
Individuare un file HTML completo
Ripetere un gruppo catturato e raggruppare un gruppo ripetuto
Esempi
Individuare tag in (X)HTML
Eliminare gli spazi vuoti
Indirizzi IP
Individuare numeri in virgola mobile
Trovare e validare un indirizzo e-mail
Individuare una data valida
Individuare una intera linea di testo
Trovare linee che contengono (o non contengono) determinate parole
Cancellare linee duplicate in un file
Rimuovere parti duplicate in una stringa
Individuare commenti
Individuare stringhe
Individuare numeri
Individuare parole particolari o parole chiave
Trovare due parole vicine l’una all’altra
Espressioni regolari per e-book
Trasformare gli spazi doppi in spazi singoli
Cancellare tutti i tabulatori
Cancellare le linee bianche (con codifica Windows)
Eliminare gli spazi vuoti di inizio riga
Eliminare gli spazi vuoti a fine riga
Eliminare le interruzione di riga interne ai paragrafi
Inserire tutte le linee tra i tag di paragrafo «
Aggiungere una «class» alle interruzioni di sezione
Aggiungere un attributo «alt» a tutte le immagini
Sostituire «&» con «&»
Sostituire apostrofi normali con apostrofi orientati
Modificare la marcatura dei titoli
Cambiare il formato delle date
Trovare caratteri speciali
Trovare caratteri speciali (escludendo apici inclinati e lineette)
Aggiungere lo stile «centrato» alle interruzioni di sezione stile Markdown
Cancellare le linee bianche con esclusione dell’ultima
Aggiungere ai capitoli lo stile «capitolo»
Sostituire i tag segnaposto nei file XHTML provenienti da file di word processor
Le sostituzioni
Gli editor di testo
EditPad (Lite|Pro) con RegexBuddy e RegexMagic
RegexBuddy
RegexMagic
Emacs
Microsoft Word
Notepad++
(Libre|Apache|Open) Office Writer
Vim
Software applicativi
Fogli di calcolo
Google Docs – Fogli
Data Base
MySQL
Le Espressioni Regolari di MySQL con l'Operatore REGEXP
Oracle
PostgreSQL
SQLite
App e shell
Apache HTTPd
Awk
Find
Grep
Nginx
PowerGrep
PowerShell
Sed
Shell Script (Bash)
Equivalenza tra glob ed espressioni regolari
Linguaggi di programmazione
C
C++
Delphi
HTML5
Java (con Groovy)
Groovy
JavaScript / ActionScript con XregExp
.NET
Perl
PHP
Il set di funzioni «preg»
Il set di funzioni «ereg»
Il set di funzioni «mb_ereg»
PCRE
POSIX
Python
Flags
Gruppi nominati
R
Ruby
Tcl
VBscript (Visual Basic)
XML
Classi di caratteri in XML
XQuery e XPath
Tre funzioni Regex
Xojo (Real Basic)
Librerie e programmi correlati
Librerie
wxWidgets
La classe wxRegEx
Funzioni di stato wxRegEx
Trovare ed estrarre occorrenze
Ricerca e Sostituzione
POSIX Base (BRE – Basic Regular Expressions)
POSIX Esteso (ERE – Extended Regular Expressions)
L'alternanza POSIX ERE restituisce l'occorrenza più lunga
Estensioni GNU delle Espressioni Regolari
GNU Basic Regular Expressions (grep, ed, sed)
GNU ERE (Extended Regular Expressions) – (egrep, awk, emacs)
Estensioni GNU addizionali
Gnulib
PCRE
Usare PCRE
Compilare PCRE con Supporto Unicode
PCRE Callout
UTF-8, UTF-16 e UTF-32
PCRE2
UTF-8, UTF-16 o UTF-32
Usare PCRE2
Sostituire le occorrenze
Programmi
Tabelle riassuntive
Differenze di metacarattere tra le applicazioni
Sintesi dei metacaratteri e dei loro dettagli
POSIX, barra-lettere e altra simbologia
Metacaratteri moderni, patch e precedenze
Caratteri ASCII stampabili (ISO-8859-1)
Prospetti riassuntivi di riferimento
Metacaratteri definiti con esempi
Escape di caratteri
Classi di caratteri
Modificatori
Lista di alcuni editor con le varianti di regex supportate
Tester per espressioni regolari
Appendice tecnica Linguaggi, grammatiche e automi
Linguaggi
Grammatiche
Linguaggi regolari ed espressioni
Espressioni regolari
Grammatiche regolari
Automi a stati finiti
Versione Deterministica
Esempi
Versione Non-deterministica
Linguaggi liberi dal contesto (context-free languages)
Grammatiche libere dal contesto (context-free grammars)
Automi a pila (pushdown automata)
Esempi
Versione non-deterministica
Esempi
Dimostrazioni
Teorema 1: Ogni linguaggio regolare è accettabile per qualche NFSA.
Teorema 2: Ogni linguaggio regolare è anche libero dal contesto.
Bibliografia essenziale
Manuali generali
Manuali su Perl con parti specifiche sulle ER
Manuali specifici
Manuali online
Manuali su automi finiti, algebre, linguaggi ed espressioni regolari
(.*?)
Prefazione
Non ricordo più quando è stato il momento preciso in cui ho scoperto le espressioni regolari, ma posso dire che da allora trattare testi è diventato molto meno faticoso.
L'utilizzo delle espressioni regolari non è molto diffuso tra autori, scrittori e redattori mentre programmatori, sviluppatori di codice e realizzatori di e-book ne fanno un frequente – e soddisfacente – impiego.
Questa succinta guida all'uso delle «regex» o «regexp» (acronimi di origine inglese da «regular expressions») o – più semplicemente – «RE», è stato pensato proprio per chi si occupa di scrivere o revisionare testi.
Delle regex esistono molte varianti (chiamate «flavours», letteralmente «sapori, gusti o aromi») ma sostanzialmente la logica è sempre la stessa e la sintassi non presenta moltissime differenze.
Qui sarà trattata la sintassi relativa alla libreria PCRE (Perl Compatible Regular Expressions) cioè a quelle istruzioni che sono accettate dai software che utilizzano un funzionamento delle regex compatibile con quello del linguaggio Perl, da cui peraltro le regex sono state derivate per un impiego operativo.
PCRE è una libreria sviluppata in linguaggio «C» ed è perciò estremamente efficiente e veloce.
Molti editor e word processor ormai incorporano la «modalità regex» per effettuare ricerche, estrazioni e sostituzioni di testo.
Un editor particolarmente utilizzato è Notepad++ ma anche il famosissimo Word di Microsoft, oppure l'open source LibreOffice (e il precedente OpenOffice) o ancora editor per lo sviluppo di software come UltraEdit o Dreamweaver e infine lo stesso Sigil, noto ai redattori di e-book in formato ePub, tutti incorporano una modalità «espressioni regolari».
Sulle espressioni regolari esiste molto poco nella letteratura in lingua italiana; ben altra mole di documentazione è invece a disposizione se si conosce un po' la lingua inglese.
Chi vorrà approfondire potrà trovare nella bibliografia alla fine di questo testo ottimi suggerimenti per le opere a stampa, di cui – il più delle volte – i loro autori forniscono anche una versione digitale, se si preferisce questa modalità di lettura.
Cosa si può fare con le regex?
Per rispondere, basta considerare che la ricerca di «stringhe» (sequenze di caratteri) da parte di un computer è molto veloce ma estremamente rigida.
Con le espressioni regolari diventa invece possibile:
– trovare se esistono nel testo determinate sequenze;
– localizzare stringhe di caratteri che combaciano con le sequenze e sostituirle con qualcosa di diverso;
– estrarre le stringhe che combaciano con le sequenze per poterle riutilizzare diversamente.
Per non annoiare troppo il lettore l'esposizione sarà legata per quanto possibile ad esempi pratici, con i quali saranno illustrate, di volta in volta, le varie funzionalità delle regex.
Ovviamente gli esempi saranno quelli che normalmente si trovano di fronte autori, scrittori e redattori.
Buona lettura!
Piove di Sacco, Dicembre 2016
Mario Canton
mario.canton@tiscali.it
Prefazione
alla seconda edizione
Con l'esperienza fatta con la prima edizione si è deciso di integrare il testo con una guida più esemplificativa, in modo da poter accostare le espressioni regolari con un taglio più didattico.
Si spera di aver ottenuto una maggiore semplicità di esposizione che renda meno ostico l'avvicinamento alle regex.
In questa seconda edizione si sono anche prese in esame le varianti (flavours) più diffuse di motori per espressioni regolari, come quelle di editor (EditPad Pro e Lite, Emacs, MS Word, Notepad++, Libre/Apache/Open Office Writer, Vim), fogli di calcolo (Google Documenti – Fogli), database (MySQL, Oracle, PostgreSQL, SQLite), app e shell (Apache HTTPd, Awk, Find, Grep, Nginx, PowerGrep, PowerShell, Sed, ShellScript o Bash), linguaggi di programmazion (C, C++, Delphi, HTML5, Java (con Groovy), JavaScript/ActionScript (con XRegExp), .NET, Perl, PHP, Python, R, Ruby, Tcl, VBScript (Visual Basic), XML, XQuery e XPath, Xojo o Real Basic), librerie (vxRegex, POSIX Base, GNU, Reggex, PCRE) e tester (text2regex, VisualRegExp, Regex Coach, RegexPal, Regex101).
Si presume che, anche se l'applicazione che si utilizza non è esplicitamente menzionata, probabilmente usi una variante che viene trattata sotto un'altra denominazione. In genere la maggior parte delle applicazioni sviluppate usano una delle varianti che sono state prese in esame, in quanto la maggior parte delle applicazioni vengono sviluppate utilizzando un ambiente di programmazione o delle librerie di espressioni regolari tra quelle considerate in questo ebook.
Si è infine integrato la parte riepilogativa con ulteriori tabulati e quadri sinottici dei comandi e degli operatori (anche relativi alle diverse varianti) e aggiunto una breve appendice tecnica sugli automi finiti, l'algebra e i linguaggi regolari, che stanno alla base della «logica» delle regex.
È stata riorganizzata la bibliografia per argomenti (trattazioni generali, Perl e regex, applicazioni specifiche, guide online e testi sulle correlazioni con gli automi a stati finiti).
Buona lettura!
Piove di Sacco, Gennaio 2018
Mario Canton
mario.canton@tiscali.it
Ringraziamenti
Vorrei ringraziare tutti gli iscritti al gruppo Idac in Facebook, per la partecipazione al sondaggio sulla scelta della copertina di questo ebook. In particolare:
Tania Adreutti
Daniela Artioli
Gaia Bay Rossi
Davide Beltrame
Laura Biagiotti
Lucia Casini
Cristiana Colpi
Rossella Di Palma
Lucia Farinati
Mara Gori
Emiliana Griotti
Maria Lentini
Daniela Maffei
Franca Maucci
Martina Mauro
Massimo Mazzucco
Emanuela Michielin
Barbara Moletta
Barbara Monici Tenconi
Orietta Piazza
Valeria Rapezzi
Paola Repetto
Riccardo Sormani
Chiara Tomiazzo
Lucia Torri
Daniela Zanrè
Due parole sulle origini
Chiunque abbia utilizzato un word processor conosce l'esistenza di funzioni che cercano e sostituiscono caratteri all'interno di un testo, sia automaticamente che su conferma da parte dell'utente.
Possiamo vedere le «espressioni regolari» come una evoluzione di questi sistemi.
Dal punto di vista storico – in realtà – le RegExp vengono molto prima dei sistemi di ricerca che si trovano nei word processor, anzi, questi ultimi sono basati proprio sulle prime, a volte su loro forme semplificate.
Le espressioni regolari si possono far risalire alle prime ricerche sul sistema nervoso umano, quando i neurofisiologi Warren McCulloch e Walter Pitts svilupparono nel 1943 un sistema matematico per la descrizione delle reti neurali.
Le «espressioni regolari» sono state sistematizzate nei successivi anni '40 da Stephen Cole Kleene, matematico statunitense, che con il suo omonimo famoso teorema afferma che sono equivalenti:
(1) la classe di linguaggi di terzo tipo (secondo Chomsky o a grammatica formale),
(2) quella dei linguaggi a stati finiti (automi a stati finiti, deterministici e non deterministici) e
(3) quella dei linguaggi regolari (espressioni regolari).
La seguente tabella sintetizza ciascuno dei quattro tipi di grammatica di Chomsky, la classe di linguaggio generata, il tipo di automa riconosciuto e le forme che devono avere le loro regole.
Sulla base di quegli studi Kleen pubblicò una ricerca che introduceva il concetto di espressione regolare che fu utilizzata per descrivere l'algebra dei «regular sets» (insiemi regolari) detta, appunto, «algebra regolare».
Le «espressioni regolari» sono state utilizzate operativamente solo dal 1966 quando furono inserite da Ken Thompson – uno dei padri del sistema operativo Unix – nell'editor chiamato QED – la prima applicazione pratica per le espressioni regolari – che veniva utilizzato come strumento di editing nelle prime versioni del sistema operativo.
Dopo gli anni '80, le «espressioni regolari» si sono diffuse ampiamente con lo sviluppo del linguaggio di programmazione Perl, creato nel 1987 da Larry Wall.
Oggi praticamente tutti i linguaggi di programmazione e moltissimi tra gli editor più avanzati – utilizzati in genere per scrivere codice – contengono un set di istruzioni relativo alle RegExp.
(.*?)
Le implementazioni
Uno dei problemi che riguardano i motori delle espressioni regolari è la loro implementazione (la realizzazione concreta delle procedure a partire dalla loro definizione logica), su cui esistono due principali orientamenti.
Per la comprensione dell'argomento è prima necessario definire cosa sia un «automa a stati finiti». Si tratta di un modello che descrive un comportamento in cui esiste un numero finito di stati e varie azioni che provocano la transizione da uno stato a un altro.
Nella Fig. 1 viene descritto l'automa a stati finiti che descrive il semplice processo di accensione e spegnimento di una lampadina (l'automa in questo caso è rappresentato dall'interruttore di energia elettrica). Questo sistema estremamente semplice ha solo due stati e due azioni che determinano due transizioni.
Lo stato iniziale è quello di «lampadina spenta». In questo stato esiste una sola possibile azione la pressione dell'interruttore che permette la transizione allo stato di «lampadina accesa». Nel nuovo stato è accessibile l'altra azione, la pressione dell'interruttore di energia elettrica che produce la transizione allo stato di «lampadina spenta».
Fig. 1 – L'automa a stati finiti che descrive l'accensione di una lampadina.
Una espressione regolare può essere rappresentata da un automa a stati finiti. Gli automi sono facilmente riproducibili da un computer, quindi è possibile usarli per creare un motore che li gestisca.
Il metacarattere quantificatore «*», come vedremo nel dettaglio più avanti, significa «zero o più». Applichiamo questo concetto cercando di tradurre con un automa l'espressione regolare «ab*c».
Nella Fig. 2 vediamo l'automa che rappresenta questa semplice espressione regolare.
Dallo stato iniziale possiamo, se incontriamo la lettera «a», passare al secondo stato. A questo punto abbiamo due alternative: possiamo incontrare la lettera «c» che ci porta allo stato finale oppure possiamo incontrare la lettera «b» che ci porta di nuovo al secondo stato.
Nota: Lo stato finale è rappresentato da un cerchio doppio.
Fig. 2 – L'automa a stati finiti dell'espressione regolare «ab*c».
Se l'automa analizza la stringa «xyabbcz» alla ricerca di una corrispondenza con l'espressione regolare «ab*c»,procedendo dalla prima lettera a sinistra e proseguendo verso destra, si verificano le seguenti fasi:
lettera «x», siamo nello stato iniziale e non possiamo fare altro, nessuna corrispondenza e passiamo alla lettera successiva;
lettera «y», siamo ancora nello stato iniziale e non possiamo fare altro, nessuna corrispondenza e passiamo alla lettera successiva;
lettera «a», siamo sempre nello stato iniziale e possiamo andare allo stato successivo, che però non è un possibile stato finale;
lettera «b», siamo nel secondo stato e possiamo effettuare una transizione verso lo stesso stato;
lettera «b», siamo ancora nel secondo stato e possiamo effettuare una transizione verso lo stesso stato;
lettera «c», siamo nel secondo stato e possiamo effettuare una transizione verso il terzo stato che è uno stato finale e ci permette di stabilire che è stata trovata una corrispondenza.
Con questi passaggi si è potuto stabilire che l'espressione regolare «ab*c» ha una corrispondenza nella stringa «xyabbcz» a partire dalla terza lettera, la «a».
Esistono due tipi di automi a stati finiti:
gli automi a stati finiti deterministici (chiamati DFA dall'inglese «Deterministic Finite Automata»
gli automi a stati finiti non deterministici (chiamati NFA dall'inglese «Non-deterministic Finite Automata»
Nei DFA, in ogni stato la transizione è determinata, in modo univoco e senza possibili ambiguità, dalla prossima lettera incontrata, come gli esempi citati.
Negli NFA in un dato stato possono esistere delle transizioni ambigue: una stessa lettera può portare a diversi stati successivi. Perciò il motore che interpreta l'automa, prima di poter stabilire se una espressione regolare individua o meno delle corrispondenze in una stringa, deve tornare sui propri passi e provare tutte le combinazioni possibili.
A esemplificazione dei concetti espressi vediamo (Figg. 3 e 4) come l'espressione regolare «(c|d)*cdd», leggermente più complessa di quella già utilizzata sopra, viene rappresentata da un NFA e da un DFA .
L'automa NFA è semplice, corrisponde in maniera diretta all'espressione regolare e in almeno un caso ha una transizione ambigua; dallo stato iniziale, se incontriamo la lettera «c» abbiamo due possibili transizioni: verso il secondo stato o indietro verso lo stato iniziale. L'espressione regolare rispecchia questa situazione; quando infatti incontriamo una lettera «c», non si può sapere se si è in presenza di una «c» che può essere ripetuta a piacere nella prima parte dell'espressione regolare «(c|d)*» o se siamo in presenza della «c» della seconda parte «cdd».
L'automa DFA è più complesso e anche più difficile da costruire, perché ha più transizioni, ma offre il vantaggio di non mettersi mai davanti a un bivio: quando si incontra all'inizio una lettera «c» si passa sempre e comunque al secondo stato e così via.
Fig.3 – L'automa a stati finiti di tipo NFA dell'espressione regolare «(c¦d)*cdd».
Fig. 4 – L'automa a stati finiti di tipo DFA dell'espressione regolare «(c|d)*cdd».
Nota: Se si prova a percorrere l'automa NFA e l'automa DFA con una stringa che corrisponda all'espressione regolare «(c|d)*cdd», per esempio «cccdcdd», si può notare che nel caso del secondo automa il percorso è sempre diretto e mai ambiguo. Nel caso del primo automa, invece, è necessario tornare indietro se si è scelto una strada sbagliata (per esempio se all'ultima «c» si è nello stato iniziale e non viene scelta la transizione che porta al secondo stato).
Esistono quindi due possibili tipi di automi che possono rappresentare una stessa espressione regolare. Nel caso degli NFA si ha una rappresentazione più semplice ma un percorso più difficile. Nel caso dei DFA si ha una rappresentazione più complessa ma un percorso più semplice e diretto.
Attualmente i due orientamenti operativi in essere seguono entrambi il metodo degli NFA, perché il problema della costruzione di un DFA a partire da un'espressione regolare può essere molto complesso e, a volte, richiedere un tempo estremamente alto. Viceversa, costruire un NFA a partire da un'espressione regolare è molto semplice e la complessità si sposta nella ricerca di un percorso verso l'individuazione di una corrispondenza.
La differenza tra i due orientamenti attuali sta nella strategia adottata per affrontare la possibile ambiguità nella scelta delle transizioni tra i diversi stati.
Un orientamento (di «backreference»), quando si trova in un vicolo cieco torna sui propri passi riprovando tutte le possibilità fino a esaurirle o fino a trovare uno stato finale.
L'altro orientamento (a «multistati»), quando si trova di fronte a un bivio percorre entrambe le strade e memorizza contemporaneamente tutti i percorsi multipli.
Nota: Questo ultimo orientamento segue l'algoritmo progettato per la prima volta da Ken Thompson nel 1968.
In termini di performance l'orientamento della backreference si comporta estremamente meglio nella grande maggioranza dei casi. L'orientamento dei multistati invece è normalmente più lento ma, con alcune espressioni regolari molto complesse (rare o del tutto inusuali), surclassa clamorosamente l'avversario.
Ad esempio, se dovessimo cercare in una stringa composta da ventinove lettere «l» consecutive:
lllllllllllllllllllllllllllll
una corrispondenza per la seguente espressione regolare:
l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?l?
il primo orientamento operativo impegnerebbe circa un minuto di CPU mentre il secondo ne impiegherebbe solo venti milionesimi di secondo. Una espressione regolare come questa non è per niente usuale, ma rimane comunque formalmente corretta.
Il problema di stabilire quale orientamento sia il migliore può essere descritto in questo modo: dobbiamo andare al lavoro; possiamo usare un‘automobile velocissima ma che potrebbe, in casi rarissimi, procedere a 2 km/h per tutto il tragitto; in alternativa possiamo usare un‘automobile più lenta ma che non ci darà mai sorprese negative.
Poiché non esiste una scelta sempre «giusta» a questa domanda, attualmente entrambi gli orientamenti hanno dei sostenitori.
Comunque, la maggior parte delle implementazioni attuali ha seguito la scuola della backreference e solo in pochi casi esistono implementazioni della scuola a multistati. Questo perché l'implementazione di un motore con la «backreference» permette di avere espressioni regolari che hanno caratteristiche avanzate, come i gruppi e le alternative (vedi oltre per i due concetti). Queste stesse caratteristiche non possono essere ottenute con un motore a multistati.
Nota: Un articolo che affronta in dettaglio la questione dei due orientamenti (scritto da Russ Cox) può essere letto (in inglese) qui: Implementazioni.
Gli automi finiti
Perché gli automi sono importanti? Una ragione è che quando hai bisogno di un'espressione regolare, a volte è più facile creare l'automa e poi derivare l'espressione regolare da quello. Quindi essere in grado di creare un automa per quello che si desidera può essere una buona abilità da possedere. In secondo luogo, alcuni programmi che accettano espressioni regolari come input, come grep e flex, convertiranno quell'espressione regolare in un automa per poi usarlo con un algoritmo molto veloce per eseguire la ricerca. Quindi è bene sapere in che modo le espressioni regolari e gli automi sono correlati. In terzo luogo, gli automi sono un modello computazionale elementare e sono molto importanti nella teoria del calcolo.
Un automa è un piccolo computer molto semplice. Ha un insieme di stati e transita da uno stato all'altro secondo la sequenza di ingressi che legge. Gli input sono solitamente rappresentati come una stringa di simboli o caratteri. Uno degli stati è lo stato di partenza e uno o più stati sono stati finali. Lo stato iniziale può anche essere uno stato finale. Il calcolo che esegue è una risposta sì o no alla domanda: la sequenza di input sposta l'automa dallo stato iniziale a uno degli stati finali? La risposta dipenderà ovviamente da come sono collegati gli stati. Esaminare come tutto questo funziona richiede alcune notazioni e definizioni formali.
Poniamo che «Q» rappresenti l'insieme di stati di un automa e poniamo che qi∈Q sia un elemento di «Q». Sia q0∈Q sia lo stato di partenza. L'automa inizia sempre in questo stato. Sia E⊆Q l'insieme degli stati finali. Se l'automa si trova in uno stato qi∈E alla fine dell'input, si dice che l'input è accettato. Gli stati finali sono talvolta chiamati stati di accettazione o stati finali. Poniamo che ∑ sia un insieme finito di simboli o caratteri chiamati alfabeto. La sequenza di input consisterà in una stringa di caratteri presi da ∑. Sia δ(qi,a)=qj la funzione di transizione dell'automa. La funzione dice che se l'automa è nello stato qi e il prossimo simbolo di input è a∈∑ allora l'automa si sposterà nello stato qj. Se l'automa è nello statoqi e legge un simbolo per il quale non è definita alcuna transizione, si ferma e l'input non viene accettato.
Come abbiamo già accennato, se un automa presenta delle transizioni o se ha uno stato con due transizioni diverse per lo stesso simbolo di input, allora è chiamato non deterministico. Altrimenti si chiama deterministico. Le sigle NFA e DFA sono usate per automi finiti non deterministici e deterministici. Ogni NFA può essere trasformato in un DFA equivalente con un numero maggiore di stati.
Un modo per caratterizzare la famiglia di stringhe accettate da un automa è un'espressione regolare (si veda la discussione nell'apposita sezione). In alcuni casi, per un piccolo automa, è possibile annotare l'espressione regolare mediante ispezione, ma in generale l'automa dovrà essere semplificato rimuovendo alcuni dei suoi stati per creare un automa equivalente più piccolo..
Si tenga presente che mentre la lingua accettata da un automa finito può essere descritta da un'espressione regolare, l'espressione regolare non deve necessariamente essere unica. È possibile avere due diverse espressioni regolari che descrivono la stessa lingua. Quando si eliminano stati in un automa, l'ordine in cui vengono eliminati a volte può portare a espressioni regolari diverse che sono ugualmente valide. Questo è analogo al fatto che è possibile avere due polinomi equivalenti, uno dei quali è una forma semplificata di un altro in cui i termini ridondanti sono stati annullati.
(.*?)
L'utilizzo
delle espressioni regolari
Questa guida operativa è finalizzate a mettere in grado chiunque di utilizzare le espressioni regolari che consentono di risparmiare moltissimo tempo nel trattamento di testi. Si inizia dai concetti più basilari, in modo che le istruzioni possano essere eseguite anche da chi non conosce ancora nulla riguardo alle espressioni regolari.
Le istruzioni tentano anche di far capire come funziona il «motore interno» delle espressioni regolari mettendo in guardia l'utilizzatore sulle eventuali conseguenze. Questo approccio aiuta a comprendere velocemente perché una particolare regex non faccia quello che inizialmente ci si aspettava. Questo risparmierà un mucchio di congetture e perplessità quando sarà necessario scrivere delle regex più complesse.
Terminologia
Fondamentalmente, una espressione regolare è un modello schematico che descrive una certa quantità di testo. Il nome deriva dalla teoria matematica su cui si basa. Ma non approfondiremo questa questione di cui qualcosa si è già detto nelle premesse. Come si è detto, appunto, il termine «espressione regolare» viene spesso abbreviato in regex (RegEx) o regexp (RegExp). Questa guida userà spesso l'abbreviazione «regex», perché più facile da pronunciare rispetto a «regexp». In questa guida le espressioni regolari sono scritte con una formattazione diversa da quella utilizzata per il testo normale, come ad esempio per «regex». Gli spazi, per essere visualizzati, sono spesso sostituiti dai punti di sospensione (tre consecutivi: ...) .
Questo primo esempio è in realtà una regex perfettamente valida. È il modello basilare, che semplicemente coincide con il testo letterale «regex». Una «coincidenza» o «occorrenza» è la porzione di testo, o sequenza di byte o caratteri che il modello schematico ha scoperto corrispondere mediante un software che processa una regex.
\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b
è già un modello schematico più complesso. Contiene una serie di lettere, numeri, punti, trattini, segni di percentuale e virgole, seguite da un segno e da un'altra serie di lettere, numeri e virgole e infine seguite da un singolo punto e due o più lettere. In altre parole: questo modello schematico descrive un indirizzo e-mail e mostra la formattazione applicata alle espressioni regolari in questa guida.
Con la suddetta espressione regolare è possibile cercare in un testo la presenza di indirizzi e-mail o verificare se una determinata stringa assomiglia ad un indirizzo e-mail. Questa guida usa il termine «stringa» per indicare il testo a cui l'espressione regolare viene applicata. Il termine «stringa» o «stringa di caratteri» viene usata dai programmatori per indicare una sequenza di caratteri. In pratica, è possibile usare le espressioni regolari con qualsiasi tipo di dati a cui sia possibile accedere utilizzando una qualsiasi applicazione (editor, word processor, analizzatore etc.) o linguaggio di programmazione in uso.
Differenti «motori» delle RegEx
Il «motore» di una espressione regolare è una porzione di software in grado di processare espressioni regolari, tentando di far combaciare il modello schematico che gli viene fornito con una determinata stringa. In genere il motore è parte di una applicazione più estesa e non è accessibile direttamente. Piuttosto, l'applicazione viene richiamata quando è necessaria, assicurando che la corretta espressione regolare sia applicata al file o ai dati corretti.
Come al solito nel mondo del software, differenti motori di espressioni regolari non sono tra loro pienamente compatibili. La sintassi e il comportamento di un particolare motore per espressioni regolari viene denominata «variante» (flavour). Questa guida copre solo le varianti più diffuse di motori per espressioni regolari, come