"Espressioni regolari"? Cos'è, matematica? Vi state sbagliando! Le espressioni regolari (o regex o regexp che dir si voglia) sono un potente formalismo ideato negli anni quaranta e implementato alla fine degli anni sessanta. Esso attualmente permette, tramite una sequenza di simboli, di definire un pattern da ricercare in una stringa qualsiasi (che potrebbe essere un file di testo, una pagina web o un database). Vediamo subito un esempio.
Estrapolare da un elenco tutte le email appartenenti al dominio turbolab.it
:
^[a-z0-9._]{1,64}@turbolab\.it$
Non allarmatevi se questa vi sembra una lingua aliena: in realtà è più semplice di quanto sembri.
uso
Moltissimi linguaggi di programmazione e varie utility supportano le regex: in questa guida mi limiterò ad utilizzare Notepad++ su Windows e grep su GNU/Linux.
Windows
Apriamo Notepad++ ed eventualmente apriamo un file.
Ora apriamo la finestra di dialogo di ricerca premendo l'icona del binocolo (oppure usiamo la scorciatoia CTRL+F
) e proviamo la nostra regex cliccando su Trova tutto nel documento corrente
, selezionando anticipatamente Tipo ricerca > Espressione regolare
.
Funziona!
GNU/Linux
Apriamo il nostro fido terminale e digitiamo grep -E "<regex>" <nomefile>
.
Nessun problema neppure qui.
Note:
- È consigliabile utilizzare l'opzione
-E
in quanto essa permette di interpretare il pattern in ingresso come una espressione regolare estesa, che in sintesi permette di avere a disposizione più operatori; - Se la nostra stringa che cerchiamo si trova vicino ad altri caratteri e se noi non vogliamo visualizzare l'intera riga, è consigliabile utilizzare l'opzione
-o
(only matching); - È sempre buona norma delimitare la regex da un paio di virgolette, in modo da non interferire con la sintassi bash.
E ora, cominciamo!
costanti
Per indicare una semplice sequenza di caratteri in una regex, è sufficiente scriverli.
Una regex contenente semplicemente TurboLab
ritornerà tutte le occorrenze trovate che corrispondono al testo TurboLab
, come una normale ricerca.
L'inizio e la fine di tutto: ^ e $
Questi due caratteri (o meglio metacaratteri) sono solitamente utilizzati all'inizio e alla fine di una regex:
-
^
indica l'inizio di una riga di testo; -
$
indica la fine di una riga di testo.
Che utilità hanno? Spieghiamolo con un esempio.
-
hello
troverà la parolahello
in righe comehello
,hello world
,hey, hello Bob!
; -
^hello$
invece troverà solamente le parole nelle righe che contengono esclusivamente la parolahello
.
Capito tutto? Adesso addentriamoci in qualcosa di più complesso e utile.
bracket expression
Una bracket expression (letteralmente espressione fra parentesi quadre) indica una lista di caratteri racchiusa tra [
e ]
, dei quali è sufficiente che solo uno combaci con i caratteri in ingresso.
Possono essere utilizzate abbreviazioni (range expression) per indicare lunghe sequenze di caratteri come l'intero alfabeto, le cifre, eccetera.
Anteponendo il carattere ^
(che non ha nessuna relazione con il carattere di inizio riga!) si possono indicare i caratteri che non devono essere inclusi.
-
[pm]azzo
troverà siapazzo
chemazzo
; -
file[0-9]\.txt
troveràfile0.txt
,file1.txt
,file2.txt
...file9.txt
; -
[a-z][^0]
troveràaa
,a1
,b9
ma nona0
b0
...z0
.
il jolly
I più attenti avranno notato che precedentemente abbiamo scritto \.
invece di .
. Non è un refuso, ma una necessità: il metacarattere .
viene utilizzato per indicare un qualsiasi carattere, ad eccezione del carattere di escape \n
.
-
ciao .
troveràciao a
,ciao 0
, ma ancheciao !
ociao @
. Per questo motivo bisogna prestare molta attenzione all'uso di questo carattere. - Se necessitiamo di utilizzare il punto come carattere possiamo, come descritto prima, dobbiamo anteporre al punto un backslash
\
.
ripetizioni
Possiamo estendere le nostre espressioni regolari con dei operatori di ripetizione. Essi "copiano" il carattere (o il gruppo di caratteri) precedente un certo numero di volte.
-
?
indica una singola ripetizione del carattere precedente facoltativa (0-1); -
*
indica una multipla ripetizione del carattere precedente facoltativa (0-X); -
+
indica una multipla ripetizione del carattere precedente non facoltativa (1-X); -
{N}
indica una ripetizione di esattamente N volte del carattere precedente (N); -
{N,}
indica una ripetizione di almeno N volte del carattere precedente (N-X); -
{,M}
indica una ripetizione di al massimo M volte del carattere precedente (0-M); -
{N,M}
indica una ripetizione compresa tra N e M volte del carattere precedente (N-M).
Esempi:
-
[0-9]?
troverà0
,1
,2
,00
,01
,99
; -
ah*
troveràa
,ah
,ahh
,ahhh
; -
ah+
troverà inveceah
,ahh
,ahhh
; -
[0-9]{10}
troverà tutti i numeri a 10 cifre (numeri telefonici?); -
[0-9]{10,}
troverà tutti i numeri a 10 o più cifre; -
[0-9]{,3}
troverà tutti i numeri con al massimo 3 cifre; -
[0-9]{2,4}
troverà tutti i numeri con 2, 3 o 4 cifre.
Conclusioni
Possiamo finalmente comprendere l'esempio citato all'inizio:
^[a-z0-9.]{1,64}@turbolab\.it$
-
[a-z0-9._]
: scelgo tutti i caratteri alfanumerici, il punto e l'underscore; -
{1,64}
: il nome utente di una mail può essere lungo fino a 64 caratteri; -
@turbolab\.it
: specifico il dominio (evito di utilizzare impropriamente il punto).
Ci sono ancora altre potenzialità nascoste dietro le regex che TurboLab.it potrebbe trattare in futuro, ma ciò che vi è stato insegnato in questo articolo vi permetterà di creare le regex di cui avete bisogno senza troppi problemi.
Segnalo infine regular-expressions.info, un sito dove potete trovare molti esempi sulle espressioni regolari.