Impariamo a usare le regex

regex

Le espressioni regolari, note anche con il termine “regex”, sono uno strumento efficiente e compatto per eseguire la ricerca e sostituzione di stringhe di caratteri all’interno di un testo. Le applicazioni sono molteplici, non solo nel campo della programmazione, ma anche nell’analisi ed elaborazione di grandi quantità di dati. Lavorate con file di testo o HTML di grosse dimensioni e non sapete come fare una particolare ricerca o sostituzione al loro interno? Volete recuperare con facilità delle informazioni da un file di log di un web server? Avete già sentito parlare delle regex ma non vi siete mai addentrati in questo affascinante mondo talvolta considerato (a torto) troppo complicato? Se la risposta è sì allora non potete perdervi questo articolo introduttivo sulle regex.

Essere in grado di capire e utilizzare le regex, talvolta chiamate anche rx o re, è sicuramente un punto a favore per ogni sviluppatore o appassionato di informatica. Ricordiamo che le regex sono riconosciute dalla maggiorparte dei linguaggi di script, come ad esempio Perl, Python, PHP, Javascript, Ruby, e sono ampiamente utilizzate negli script utilizzati sui sistemi operativi Unix e Linux. Non solo, diversi IDE, editor (ad esempio Notepad++, vi e vim), e ambienti di sviluppo supportano oggi le espressioni regolari.
Qual’è l’utilità delle espressioni regolari?

Come anticipato precedentemente, le espressioni regolari sono un modo estremamente compatto per eseguire la ricerca (come anche la sostituzione) di specifici caratteri, combinazioni di caratteri, o parole, all’interno di un testo anche molto ampio. Un esempio di espressione regolare, con cui penso tutti i lettori abbiano avuto a che fare con l’utilizzo quotidiano del computer, è l’utilizzo delle “wildcard” per selzionare un gruppo di file. Possiamo ad esempio restringere la selezione ai soli file con estensione .txt tramite la nota espressione *.txt. Anche se molto semplice, questo è un esempio di regex. Ovviamente, le regex sono in grado di fare molto di più..

Per imparare a utilizzare correttamente le regex, verificando direttamente la validità delle espressioni regolari scritte, è utile e consigliabile impiegare uno strumento di test. Un esempio molto valido è rappresentato dal tool regexpal, che non richiede alcuna installazione in quanto si tratta di un’applicazione disponibile online a questo indirizzo (si tratta in pratica di un programma di test per le espressioni regolari scritto in Javascript). In regexpal lo schermo viene diviso in due parti: in quella inferiore andrà inserito il testo sul quale si desidera testare (cioè applicare) l’espressione regolare, mentre nella parte superiore si digiterà l’espressione regolare stessa. Nell’immagine seguente è mostrata la schermata di benvenuto dell’applicazione regexpal.

RICERCA DI STRINGHE

Cominciamo a esaminare le regex utilizzate per la ricerca di stringhe di caratteri. Successivamente vedremo anche il caso della ricerca e sostituzione. Occorre inoltre tenere presente che le espressioni regolari sono case sensitive (a meno di utilizzare esplicitamente un modificatore che vedremo in seguito), e pertanto c’è differenza tra lettere maiuscole e minuscole.

Ricerca letterale

E’ il caso più semplice di espressione regolare, e consiste nella ricerca “letterale” di uno o più caratteri, numeri, o simboli. Espressioni regolari di questo tipo sono ad esempio ca, s, 12, ecc.

Consideriamo ora il testo formato dalle parole casa, cava, cane, sentiero, 1, 12, 123, 2012, e supponiamo di applicare a questo testo le regex citate precedentemente. Il risultato sarà il seguente (potete verificarlo tramite regexpal).

Nota: le sequenze di caratteri che corrispondono all’espressione regolare (che cioè la “matchano”, perdonate il neologismo) vengono sottolineati e scritti in grassetto, mentre regexpal usa un meccanismo di evidenziazione con colori giallo e blu alternati.

ca

casa, cava, cane, sentiero, 1, 12, 123, 2012
s

casa, cava, cane, sentiero, 1, 12, 123, 2012
12

casa, cava, cane, sentiero, 1, 12, 123, 2012

I metacaratteri

I metacaratteri sono dei caratteri speciali che, anzichè essere utilizzati essi stessi per eseguire una ricerca letterale, svolgono una determinata funzione. Un esempio di metacarattere è il carattere punto (‘.’), la cui funzione è quella di trovare corrispondenza (match) con qualunque carattere tranne il newline. Applichiamo ad esempio l’espressione regolare c..a al testo precedente. Il risultato sarà il seguente:

c..a

casa, cava, cane, sentiero, 1, 12, 123, 2012

In pratica vengono accettate (“matchate”) tutte le sequenze di 4 caratteri che iniziano con una ‘c’ e terminano con una ‘a’.

Parlando di metacaratteri, sorge spontanea una domanda: come posso fare a riconoscere all’interno di una sequenza di caratteri proprio un metacarattere? La risposta è la seguente: uso la tecnica di “escaping”. In pratica, faccio precedere il metacarattere da un backslash (‘\’) che l’interprete di espressioni regolari riconosce come un escape (quindi sa che il carattere successivo non va interpretato come metacarattere, ma come un carattere qualsiasi). Ad esempio, se vogliamo trovare il carattere punto all’interno di un testo useremo la seguente regex:

\.

Oggi è una bella giornata. Andiamo a fare un giro in bici?

Come esercizio, provate a rimuovere il carattere backslash nell’espressione regolare precedente. Cosa succede?

Oltre al punto, esistono altri metacaratteri utilizzati nelle espressioni regolari. Vediamoli assieme.

Il punto di domanda (‘?’) accetta zero oppure una sola occorrenza dell’elemento che lo precede. Esempio:

pol?lo

polo
pollo
polio

L’asterisco (‘*’) accetta invece zero oppure più occorrenze dell’elemento che lo precede. Esempio:

10*

1
10
100
1000
10000
112

Simile al precedente è il segno più (‘+’), che accetta una oppure più occorrenze dell’elemento che lo precede. Esempio:

bos+

bo
bos
boss

Il quantificatore numerico singolo {n} trova esattamente il numero n di occorrenze del carattere che lo precede. Esempio:

0{3}

1
10
100
1000
10000
100000

La logica estensione di quest’ultimo tipo di quantificatore è rappresentata dal quantificatore numerico con range {n, m} che trova il numero di occorrenze compreso tra n (minimo) e m (massimo) del carattere che lo precede. Esempio:

0{3,4}

1
10
100
1000
10000
100000

Per rappresentare una scelta alternativa tra due o più possibili soluzioni si utilizza il metacarattere ‘|’ (l’OR utilizzato da molti linguaggi di programmazione e di scripting). Esempio:

luca | giorgio

luca giovanni giorgio nicola

Come si fa ad applicare i quantificatori appena visti a un gruppo di elementi? E’ ad esempio possibile applicare il quantificatore {n} non a un singolo carattere ma a un gruppo di caratteri? La risposta è affermativa: basta utilizzare le parantesi tonde per raggruppare gli elementi. Esempio:

(co){2,3}

co
coco
cococo

Oppure, combiando tra loro più metacaratteri:

lu(n|l)a

luca
luna
lupa
lula

I raggruppamenti ottenibili con le parentesi tonde sono ampiamente utilizzati per memorizzare temporaneamente dei pattern (vale a dire delle espressioni che corrispondono alla regex) che possono poi essere richiamati successivamente per eseguire una sostituzione (replace). Per richiamare un match memorizzato in precedenza si usa la notazione \x, dove x=1 per il primo match, x=2 per il secondo, e così via. Per chiarire meglio questo concetto consideriamo il seguente esempio. Supponiamo che si vogliano controllare degli indirizzi e-mail, analizzando una lista contenente nome, cognome, e indirizzo di posta elettronica degli utenti iscritti a un determinato sito. Supponiamo che la regola sia la seguente: sono validi tutti e soli gli indirizzi espressi nella forma nome.cognome@xyz.abc, dove sia nome che cognome sono composti da un minimo di 2 fino a un massimo di 10 caratteri. Si avrà allora:

(.{2,10}) (.{2,10}) \1\.\2@xyz.abc

mario rossi mario.rossi@xyz.abc
Piero Bianchi Piero.Bianchi@xyz.abc
luca giovanni luca_giovanni@xyz.abc

Sempre nella categoria dei metacaratteri, un ruolo importantissimo è svolto dalle classi di caratteri, rappresentate attraverso le parantesi quadre (‘[‘ e ‘]’). Quando un insieme di uno o più caratteri viene racchiuso tra parantesi quadre, viene accettato uno qualsiasi tra questi caratteri, ma non più di uno. Esempio:

[abc]de

ade
bde
cde
abde
bcde
acde

Se ad esempio vogliamo trovare tutti i numeri compresi tra 0 e 9 possiamo usare la classe [0123456789]. Può essere noioso dover inserire tutto l’elenco dei caratteri ammissibili in una classe, e pertanto nelle espressioni regolari sono state definite delle scorciatoie (shortcut) per agevolare questo compito. Ad esempio la classe [0-9] si riferisce a tutte le cifre comprese tra 0 e 9 (molto più sintetica della precedente!), le classi [a-z] e [A-Z] alle lettere dell’alfabeto minuscole e maiuscole, rispettivamente. Le classi possono inoltre essere combinate con i quantificatori, al fine di trovare più occorrenze di uno dei caratteri elencati nella classe. Supponiamo di voler trovare tutti i numeri di due cifre compresi tra 10 e 99. L’espressione regolare corrispondente sarà:

[0-9]{2}

10
99
1
0
50
100

I caratteri all’interno di una classe (quelli cioè racchiusi tra parentesi quadre) possono anche essere “negati”, nel senso che ci interessa trovare ad esempio tutti i carattere tranne quelli elencati nella classe. Per svolgere questa funzione si utilizza il carattere “caret” (‘^’) che va inserito dopo la prima parentesi quadra. Ad esempio la notazione [^0-9] indica che siamo interessati a tutti i caratteri tranne le cifre decimali da 0 a 9. Un esempio un pò più articolato è il seguente:

[^5-9][A-F]

1A
4F
50
5C
9F

A seconda del particolare linguaggio di scripting utilizzato per scrivere le espressioni regolari, possono poi esistere o meno altre classi di caratteri (shortcut) in grado di semplificare l’espressione stessa.

Ecco le più comuni:

\d cifra tra 0 e 9 (equivale a [0-9]

\D tutto tranne le cifre tra 0 e 9 (opposto di \d)

\w word (equivale a [a-zA-Z_]

\W non word

\xhh carattere esadecimale hh

\Oxxx carattere ottale xxx

\s carattere spazio

\S tutti i caratteri tranne lo spazio

\c carattere di controllo

Si noti come l’opposto di una classe sia rappresentato tramite la stessa lettera dell’alfabeto ma in maiuscolo anzichè minuscolo. Inoltre, gli opposti di una classe possono sempre essere ricavati (in modo alternativo) utilizzando il caret visto precedentemente.

Due metacaratteri particolari sono gli “anchor”, rappresentati dai caratteri ‘^’ (inizio riga) e ‘$’ (fine riga). Il carattere caret non va confuso con quello visto in precedenza relativamente alle classi. O meglio, per evitare confusione basta ricordarsi che il caret quando è all’interno delle parentesi quadre funge da negazione per i caratteri della classe, mentre quando è all’esterno delle parentesi quadre (e presumibilmente all’inizio dell’espressione regolare) identifica il carattere di inizio riga. Supponiamo ad esempio di voler trovare all’interno di un testo tutte le righe che iniziano con l’articolo “La”. L’espressione regolare corrispondente sarà la seguente (se usate regexpal, ricordatevi di spuntare l’opzione “^$ match at line break):

^La.*

La
Lalla
la
Lo
Gli

RICERCA E SOSTITUZIONE

Le espressioni regolari possono essere efficacemente utilizzzate come uno strumento di ricerca e sostituzione (search and replace). La sintassi dipende anche in questo caso dal particolare linguaggio di scripting utilizzato, comunque la forma più generale (corrispondente a quella utilizzata dal Perl) è la seguente: /ricerca/sostituzione/modificatore. Il campo “ricerca” sarà una stringa di caratteri contenente nè più nè meno un’espressione regolare come quelle viste negli esempi precedenti, mentre il campo “sostituzione” sarà una normale stringa di caratteri. I modificatori li vedremo successivamente. Supponiamo di voler cercare all’interno di un testo tutti gli indirizzi del tipo http://www.*.com (ad esempio http://www.abc.com e http://www.def.com) e cambiarli in http://www.*.it (http://www.abc.it e http://www.def.it). Per testare un’espressione regolare di ricerca e sostituzione conviene utilizzare un editor di testo in grado di supportare questa funzionalità, come ad esempio Notepad++ (liberamente scaricabile qui. Inseriamo in un file di testo due righe con il seguente contenuto:



http://www.abc.com


http://www.boh.com


Apriamo poi la finestra di Replace, spuntiamo la checkbox “Regular expression” e inseriamo le espressioni:

http://www\.(\w+)\.com nella casella “Find what:” e

http://www.\1.it nella casella “Replace with:”

Premiamo quindi il tasto “Replace All” e le sostituzioni desiderate avverranno in un sol colpo.

In precedenza si è accennato ai modificatori. La loro funzione è quella di modificare, appunto, il comportamento di un’espressione regolare. Uno di questi è rappresentato dalla lettera ‘i’, il cui significato è quello di ignorare le maiuscole e minuscole (l’espressione diventa quindi “case insensitive”).

Esistono altri tipi di modificatori, come ad esempio:

m  – gestisce le linee multiple

s   –  considera la stringa come una linea singola

x  –  consente di inserire commenti e spazi

g  –  global match

In questo breve tutorial abbiamo visto i fondamenti che stanno alla base delle espressioni regolari. Poichè queste rappresentano uno strumento essenziale per l’attività di sviluppo, è importante conoscerle e saperle utilizzare. Il modo migliorare è quello di approfondire la pratica esercitandosi con i casi reali che si presentano nell’attività di sviluppo quotidiana.

 

Quello che hai appena letto è un Articolo Premium reso disponibile affinché potessi valutare la qualità dei nostri contenuti!

 

Gli Articoli Tecnici Premium sono infatti riservati agli abbonati e vengono raccolti mensilmente nella nostra rivista digitale EOS-Book in PDF, ePub e mobi.
volantino eos-book1
Vorresti accedere a tutti gli altri Articoli Premium e fare il download degli EOS-Book? Allora valuta la possibilità di sottoscrivere un abbonamento a partire da € 2,95!
Scopri di più

3 Comments

  1. slovati slovati 23 ottobre 2012
  2. Emanuele Emanuele 24 ottobre 2012
  3. Piero Boccadoro Piero Boccadoro 25 ottobre 2012

Leave a Reply