Il piano didattico del primo anno del corso di laurea triennale in Informatica, presso l’Università degli Studi di Milano, include l’insegnamento di Linguaggi formali e automi. Uno degli argomenti fondamentali è la grammatica formale, che trova applicazione nelle espressioni regolari di Unix. Sebbene ci siano numerosi materiali didattici online che catturano l’attenzione dei principianti, una risorsa imprescindibile, nonché testo di riferimento per il corso stesso, è “Introduction to Automata Theory, Languages and Computation” di Hopcroft e Ullman del 1979 (tradotto anche in italiano).
Poiché il corso inizia nei freddi giorni di febbraio, posso posticipare la lettura e la discussione di questo autentico capolavoro letterario ai primi mesi del nuovo anno. Pertanto, ho ritenuto opportuno iniziare lo studio oggi dai siti web che trattano in modo rigoroso l’uso delle espressioni regolari nel linguaggio di programmazione Go (o Golang, per gli amici), insegnato nel primo semestre accademico. È ragionevole presumere che il lettore abbia già una certa familiarità con questo linguaggio.
La mia ricerca mi ha condotto al sito ufficiale di Go, ricco di informazioni su ogni aspetto tecnico e pratico del linguaggio, dove l’implementazione della ricerca tramite espressioni regolari è trattata in modo esaustivo. Il pacchetto di riferimento è chiamato ‘regexp’ e fa parte della libreria standard.
Espressioni regolari secondo Google Link to heading
Un’espressione regolare definisce un insieme di stringhe; se una qualsiasi di queste stringhe appartiene a tale insieme, si afferma che l’espressione regolare corrisponde (preferibilmente si può dire coincide o si abbina) alla stringa. In inglese si usa il termine matches.
Definizione Link to heading
(Paul Wankadia). Le espressioni regolari sono una notazione per descrivere insiemi di stringhe di caratteri (i linguaggi).
Un letterale è l’espressione regolare più semplice, composta da un singolo
carattere alfanumerico. Con l’eccezione dei metacaratteri, che assumono un
significato particolare nell’espressione regolare, i letterali coincidono
sempre con sé stessi. Quando è necessario interpretare un metacarattere nel suo
significato letterale piuttosto che come parte di un’espressione regolare, è
necessario anteporgli una barra rovesciata. Ad esempio, i seguenti caratteri
sono considerati metacaratteri: *
+
?
()
|
Proposizione Link to heading
(Paul Wankadia). Due espressioni regolari possono essere scambiate oppure concatenate per formare una nuova espressione regolare.
Supponiamo di avere due espressioni regolari, e1 e e2, tali che e1
coincide con la stringa s e e2 coincide con la stringa t. Allora,
l’espressione regolare ottenuta accostando e1, il metacarattere | e
l’espressione regolre e2 (cioè e1|e2
) coincide con la stringa s oppure
con la stringa t. Al contrario, l’espressione regolare ottenuta concatenando
e1 ed e2 (cioè e1e2
) coincide con la stringa st.
Volendo mettere in pratica quanto appena esposto, scriviamo il seguente
programma che utilizza la struttura Regexp
e il metodo MatchString
per
rappresentare una espressione regolare e verificare se essa coincide con una
stringa.
Programma Link to heading
Dopo aver precisato la clausola di programma e la dichiarazione che importa
i due pacchetti della libreria standard, fmt
e regexp
, si procede definendo
nel blocco main
due variabili di tipo stringa e1
, e2
per memorizzare
le espressioni regolari ho
e tel
; a questo punto si chiama il metodo
MustCompile
della struttura Regexp
per compilare l’espressione regolare
e1
e si eseguono alcune semplici ricerche: MustCompile
può essere
considerato il costruttore dell’oggetto Regexp
con il quale è poi possibile
effettuare una serie di operazioni su stringhe con il metodo MatchString
,
in questo caso tutte abbastanza semplici. La prima operazione cerca nella
stringa ad hoc l’espressione ho
e siccome c’è un riscontro (quarto e quinto
letterale), il programma stampa true (vero); nella seconda il riscontro
fallisce in quanto la stringa otel non coincide in nessun punto con
l’espressione compilata ho
e il programma stampa false (falso).
Abbiamo quindi raggiunto i seguenti risultati:
-
c’è un riscontro tra l’espressione regolare
e1=ho
e la stringa ad hoc. -
Non c’è nessun riscontro tra l’espressione regolare
e1=ho
e la stringa otel.
Il passo successivo è provare l’alternativa tra le espressioni regolari e1
, e2
.
A tal scopo, viene creata (ma sarebbe persino superfluo) una nuova variabile e3
di tipo stringa per memorizzare l’espressione regolare e1|e2
tramite
l’operazione di concatenazione permessa dal linguaggio di programmazione e si
ricompila con il metodo ormai noto. Si compiono quattro ricerche: si cerca per
ho
oppure tel
in ote, ma fallisce perché la stringa non appartiene
all’insieme descritto dall’espressione regolare e3
; la seconda ricerca porta
i suoi frutti, l’espressione regolare e2=tel
(che fa parte di e3
) combacia
con gli ultimi tre letterali di otel; la terza ricerca ha successo, infatti
viene riscontrata l’espressione regolare e1=ho
in hote; anche l’ultima
operazione ha un esito positivo, di nuovo e1=ho
è presente in hotel e questo
e sufficiente per il programma.
I seguenti risultati sono stati raggiunti:
-
non c’è nessun riscontro tra la stringa ote e l’espressione regolare
e1=ho
e neppure cone2=tel
. -
Viene riscontrata l’espressione
e2=tel
in otel -
Viene riscontrata l’espressione
e1=ho
in hote -
Viene riscontrata l’espressione
e1=ho
in hotel
Chiaramente, il processo di riscrivere e ricompilare le espressioni è ripetitivo e laborioso, seppure istruttivo. Fortunatamente, esistono programmi, sia da riga di comando sia con interfaccia grafica, che consentono ricerche avanzate con le espressioni regolari su stringhe di testo. Inoltre, sono disponibili applicazioni Web per costruire e verificare la correttezza di tali espressioni, le quali hanno un impatto positivo significativo sul lavoro del programmatore. Infine, consapevole di aver dato per scontate molte nozioni di programmazione, mi impegno a tornare su questo affascinante argomento, sperando di esaminarlo in dettaglio sotto ogni aspetto.
Licenza GNU FDL