[successivo] [precedente] [inizio] [fine] [indice generale] [indice analitico]


Capitolo 2.   Espressioni regolari standard

L'espressione regolare è un modo per definire la ricerca di stringhe attraverso un modello di comparazione. Viene usato da diversi programmi di servizio, ma non tutti aderiscono agli stessi standard. In questo capitolo si vuole descrivere lo standard POSIX al riguardo.

Questo tipo di definizione non vale in generale e non corrisponde nemmeno ad alcuna situazione pratica in cui vengono utilizzate le espressioni regolari con i programmi che si trovano generalmente con GNU/Linux. Tuttavia, è un riferimento utile per comprendere meglio la filosofia che sta alla base delle espressioni regolari.

Per studiare la grammatica delle espressioni regolari, occorre abbandonare qualunque resistenza, tenendo presente che l'interpretazione di queste espressioni va fatta da sinistra a destra; inoltre, ogni simbolo può avere un significato differente in base al contesto in cui si trova.

Raramente si può affermare che un'espressione regolare sia «errata»; nella maggior parte dei casi in cui si commettono degli errori, si ottiene comunque qualcosa che può avere un significato (indipendentemente dal fatto che questa possa avere o meno una corrispondenza). È ancora più difficile che una realizzazione in cui si utilizzano le espressioni regolari sia in grado di segnalare un errore grammaticale nella loro scrittura.

2.1   RE: BRE, ERE e SRE

Un'espressione regolare, come definita nello standard POSIX 1003.2, può essere espressa attraverso due tipi di grammatiche differenti: le espressioni regolari di base, o elementari, identificate dall'acronimo BRE (Basic Regular Expression), e le espressioni regolari estese, identificate dall'acronimo ERE (Extended Regular Expression). La grammatica delle espressioni regolari tradizionali degli ambienti Unix viene identificata dall'acronimo SRE (Simple Regular Expression); in generale, per fare riferimento a espressioni regolari non meglio definite, si usa anche soltanto l'acronimo RE.

Attualmente si fa riferimento soltanto a espressioni regolari di tipo BRE o di tipo ERE, dipendendo dal programma di servizio la scelta tra l'una o l'altra forma. In generale, la necessità di definire un modello grammaticale differente da SRE dipende dalla presenza di problemi legati alla localizzazione.

2.2   Problemi di localizzazione

L'espressione regolare, essendo un mezzo per identificare una porzione di testo, risente di problemi legati alle definizioni locali degli insiemi di caratteri.

Per prima cosa occorre considerare che gli alfabeti nazionali sono differenti da un linguaggio all'altro. Dal punto di vista della localizzazione, gli elementi che compongono gli alfabeti sono degli elementi di collazione (collating element). Questi elementi compongono un insieme ordinato, definito sequenza di collazione (collating sequence), che permette di stabilire l'ordine alfabetico delle parole. In situazioni particolari, alcuni elementi di collazione sono rappresentati da più di un carattere, cosa che può dipendere da motivazioni differenti. Per fare un esempio comune, questo può essere causato dalla mancanza del carattere adatto a rappresentare un certo elemento, come succede nella lingua tedesca quando si utilizza un insieme di caratteri che non dispone delle vocali con la dieresi, oppure manca la possibilità di indicare la lettera «ß»:

ß       --> ss
ä       --> ae
ö       --> oe
ü       --> ue

Nella lingua tedesca, nel momento in cui si utilizzano le stringhe «ae», «oe», «ue» e «ss», in sostituzione delle lettere che invece avrebbero dovuto essere utilizzate, queste stringhe vanno considerate come la rappresentazione di tali lettere, costituendo così un elemento di collazione unico. Per esempio, in tedesco la parola «schal» viene prima di «schälen», anche se quest'ultima fosse scritta come «schaelen».

Ai fini della definizione di un'espressione regolare, questo fatto si traduce nella possibilità di fare riferimento a degli elementi di collazione attraverso la stringa corrispondente, nel momento in cui non è possibile, o non conviene usare il carattere che lo rappresenta simbolicamente in base a una codifica determinata. Tuttavia, il testo su cui si esegue la ricerca attraverso un'espressione regolare, viene interpretato a livello di carattere, e non è possibile identificare un elemento di collazione in una sottostringa composta da più caratteri. In pratica, un'espressione regolare non riuscirebbe a riconoscere l'elemento ae nella parola schaelen.

Alcuni elementi di collazione possono essere classificati come equivalenti. Per esempio, nella lingua italiana le lettere «e», con o senza accento, rappresentano questo tipo di equivalenza. Gli elementi di collazione «equivalenti» costituiscono una classe di equivalenza.

Infine, i caratteri (e non più gli elementi di collazione) possono essere classificati in base a diversi altri tipi di sottoinsiemi, a cui si fa riferimento attraverso dei nomi standard. In generale si tratta di distinguere tra: lettere maiuscole, lettere minuscole, cifre numeriche, cifre alfanumeriche, ecc.

2.3   Composizione di un'espressione regolare e corrispondenza

Un'espressione regolare è una stringa di caratteri, che nel caso più semplice rappresentano esattamente la corrispondenza con la stessa stringa. All'interno di un'espressione regolare possono essere inseriti dei caratteri speciali, che permettono di rappresentare delle corrispondenze in situazioni più complesse. Per fare riferimento a tali caratteri in modo letterale, occorre utilizzare delle tecniche di protezione, che variano a seconda del contesto.

I caratteri speciali sono tali solo nel contesto per il quale sono stati previsti. Al di fuori di quel contesto possono essere caratteri normali, o caratteri speciali con un significato differente.

La corrispondenza tra un'espressione regolare e una stringa, quando avviene, serve a delimitare una sottostringa che può andare dalla dimensione nulla fino al massimo della stringa di partenza. È importante chiarire che anche la corrispondenza che delimita una stringa nulla può avere significato, in quanto identifica una posizione precisa nella stringa di partenza. In generale, se sono possibili delle corrispondenze differenti, viene presa in considerazione quella che inizia il più a sinistra possibile e si estende il più a destra possibile.

2.3.1   Ancoraggio iniziale e finale

In condizioni normali, un'espressione regolare può individuare una sottostringa collocata in qualunque posizione della stringa di partenza. Per indicare espressamente che la corrispondenza deve iniziare obbligatoriamente dall'inizio della stringa, oppure che deve finire esattamente alla fine della stringa stessa, si usano due ancore, rappresentate dai caratteri speciali ^ e $, ovvero dall'accento circonflesso e dal dollaro.

Per la precisione, un accento circonflesso che si trovi all'inizio di un'espressione regolare identifica la sottostringa nulla che si trova idealmente all'inizio della stringa da analizzare; nello stesso modo, un dollaro che si trovi alla fine di un'espressione regolare identifica la sottostringa nulla che si trova idealmente alla fine della stringa stessa. Nel caso particolare delle espressioni regolari BRE, i caratteri ^ e $ hanno questo significato anche nell'ambito di una sottoespressione, all'inizio o alla fine della stessa. Una sottoespressione è una porzione di espressione regolare delimitata nel modo che verrà mostrato in seguito.

Per fare un esempio, l'espressione regolare ^ini corrisponde alla sottostringa ini della stringa inizio. Nello stesso modo, l'espressione regolare ini$ corrisponde alla sottostringa ini della stringa scalini.

Un'espressione regolare può contenere entrambe le ancore di inizio e fine stringa. In tal caso si cerca la corrispondenza con tutta la stringa di partenza.

2.3.2   Delimitazione di una o più sottoespressioni

Una sottoespressione è una porzione di espressione regolare individuata attraverso dei delimitatori opportuni. Per la precisione, si tratta di parentesi tonde normali nel caso di espressioni regolari ERE (estese), oppure dei simboli \( e \) nel caso di espressioni regolari BRE.

La delimitazione di sottoespressioni può servire per regolare la precedenza nell'interpretazione delle varie parti dell'espressione regolare, oppure per altri scopi che dipendono dal programma in cui vengono utilizzate. In generale, dovrebbe essere ammissibile la definizione di sottoespressioni annidate.

Per fare un esempio, l'espressione regolare BRE \(anto\)logia corrisponde a una qualunque sottostringa antologia. Nello stesso modo funziona l'espressione regolare ERE (anto)logia.

2.3.3   Riferimento a una sottoespressione precedente (solo BRE)

Nelle espressioni regolari di tipo BRE è possibile utilizzare la forma \ n, dove  n  è una cifra numerica da uno a nove, per indicare la corrispondenza con l' n -esima sottoespressione precedente. Per esempio, l'espressione regolare \(sia\) questo \1 corrisponde alla sottostringa sia questo sia di un testo che può essere anche più lungo.

È importante osservare che la corrispondenza della forma \ n rappresenta ciò che è stato trovato effettivamente attraverso la sottoespressione, mentre se si volesse semplicemente ripetere lo stesso modello, basterebbe riscriverlo tale e quale.

2.3.4   Sottoespressioni alternative (solo ERE)

Esclusivamente nelle espressioni regolari ERE (estese), è possibile indicare la corrispondenza alternativa tra due modelli utilizzando il carattere speciale | (la barra verticale). Di solito si utilizza questa possibilità delimitando espressamente le sottoespressioni alternative, in modo da evitare ambiguità, tuttavia questo non dovrebbe essere necessario, dal momento che si tratta di un operatore con un livello molto basso di precedenza.

Per esempio, l'espressione regolare ((auto)|(dog))matico) può corrispondere indifferentemente alla sottostringa automatico oppure dogmatico.

2.3.5   Corrispondenza con un carattere singolo

In un'espressione regolare, qualsiasi carattere che nel contesto non abbia un significato particolare, corrisponde esattamente a se stesso.

Il carattere speciale . (il punto), rappresenta un carattere qualunque, a esclusione di <NUL>. Per esempio, l'espressione regolare nuo.o corrisponde a nuoto, nuovo, e ad altre sottostringhe simili. Per indicare un punto letterale, occorre utilizzare l'espressione \. (barra obliqua inversa, punto).

È possibile definire anche la corrispondenza con un carattere scelto tra un insieme preciso, utilizzando una notazione speciale, ovvero un'espressione tra parentesi quadre:

[ elenco_corrispondente ]
[^ elenco_non_corrispondente ]

Come si vede dallo schema sintattico, si distinguono due situazioni fondamentali: nel primo caso si definisce un elenco di corrispondenze; nel secondo si ottiene questa definizione indicando un elenco di caratteri che non si vogliono trovare. Si osservi che per negare l'elenco di corrispondenze si utilizza l'accento circonflesso, che quindi assume qui un significato speciale, differente dall'ancora di inizio già descritta.

L'elenco tra parentesi quadre può essere un elenco puro e semplice di caratteri (lungo a piacere), per cui, per esempio, l'espressione regolare piccol[aieo] corrisponde indifferentemente alle sottostringhe piccolo, piccoli, piccole, e piccolo. In alternativa può essere rappresentato attraverso uno o più intervalli di caratteri, ma questo implica delle complicazioni che verranno descritte in seguito.

Per negare un elenco, lo si fa precedere da un accento circonflesso. Per esempio, l'espressione regolare aiut[^ia] può corrispondere alla sottostringa aiuto e anche a molte altre, ma non può corrispondere né ad aiuti, né ad aiuta.

Dal momento che l'accento circonflesso ha un significato speciale se appare all'inizio di tale contesto, questo può essere usato in modo letterale solo in una posizione più avanzata.

Infine, per indicare una parentesi quadra aperta letterale in un contesto normale, al di fuori delle espressioni tra parentesi quadre, basta l'espressione \[.

2.3.6   Corrispondenze multiple

Alcuni caratteri speciali fungono da operatori che permettono di definire e controllare il ripetersi di un modello riferito a un carattere precedente, a una sottoespressione precedente, oppure a un riferimento all'indietro delle espressioni regolari BRE.

In tutti i tipi di espressione regolare, l'asterisco (*) corrisponde a nessuna o più ripetizioni di ciò che gli precede. Per esempio, l'espressione regolare aiuto* corrisponde alla sottostringa aiut, oppure aiuto, come anche ad aiutoooooooo, ecc. Inoltre, è il caso di osservare che l'espressione regolare .* corrisponde a qualunque stringa, di qualunque dimensione.

Per indicare un asterisco letterale in un contesto normale, basta farlo precedere da una barra obliqua inversa: \*.

Nel caso di espressioni regolari ERE si possono utilizzare anche gli operatori + e ?, per indicare rispettivamente una o più occorrenze dell'elemento precedente, oppure zero o al massimo un'occorrenza di tale elemento. Per esempio, l'espressione regolare aiuto+ corrisponde alla sottostringa aiuto, oppure aiutoo, aiutooooo, ecc., mentre l'espressione regolare aiuto? può corrispondere alla sottostringa aiut, oppure aiuto.

Le espressioni regolari BRE e ERE permettono l'utilizzo di un'altra forma più precisa e generalizzata per esprimere la ripetizione di qualcosa. Nel caso di BRE si usano i modelli

\{ n \}
\{ n ,\}
\{ n , m \}

mentre nel caso di ERE si usano forme equivalenti senza le barre oblique inverse:

{ n }
{ n ,}
{ n , m }

Si tenga presente che  n  rappresenta un numero non negativo, mentre  m , se utilizzato, deve essere un numero maggiore di  n .

Nella prima delle tre forme, si intende indicare la ripetizione di  n  volte esatte l'elemento precedente; nella seconda si intendono almeno  n  volte; nella terza si intendono tante ripetizioni da  n  a  m . In generale, per garantire che un'espressione regolare sia portabile, occorre che il limite massimo rappresentato da  m  non superi 255.

2.4   Espressioni tra parentesi quadre

Si è accennato all'uso delle espressioni tra parentesi quadre, per indicare la scelta tra un elenco di caratteri, o tra tutti i caratteri esclusi quelli dell'elenco. Un'espressione del genere si traduce sempre nella corrispondenza con un carattere singolo. All'interno di un'espressione del genere, si possono utilizzare forme particolari per indicare un carattere, attraverso un simbolo di collazione, una classe di equivalenza, oppure attraverso una classe di caratteri. È molto importante anche la possibilità di definire degli intervalli, che è stata saltata volutamente nella descrizione precedente di queste espressioni.

2.4.1   Corrispondenza con un elemento di collazione

Se si hanno difficoltà a indicare dei caratteri in un'espressione tra parentesi quadre, potrebbe essere opportuno indicarli attraverso l'elemento di collazione corrispondente. Supponendo che nella localizzazione utilizzata esista l'elemento di collazione ae, identificato dal simbolo di collazione <ae>, mancando la possibilità di usare il carattere corrispondente, questo si potrebbe esprimere nella forma [.ae.].

In generale, è possibile indicare un carattere singolo all'interno dei delimitatori [. e .], come se fosse un elemento di collazione. Per esempio, [.a.] è perfettamente uguale all'espressione a. In questo modo, si può usare la tecnica di rappresentazione degli elementi di collazione quando il contesto rende difficile l'indicazione di qualche carattere.

È necessario ribadire che il simbolo di collazione può apparire solo all'interno di un'espressione tra parentesi quadre. Per fare un esempio pratico, trovandoci in una localizzazione adatta, volendo scrivere un'espressione regolare che corrisponda alla sottostringa schälen, e non potendo rappresentare il carattere ä, si dovrebbe scrivere: sch[[.ae.]]len, dove [.ae.] è il simbolo di collazione che dovrebbe corrispondere al carattere ä.

2.4.2   Corrispondenza con una classe di equivalenza

Nell'ambito della sequenza di collazione della localizzazione che si usa, alcuni elementi possono essere considerati equivalenti ai fini dell'ordinamento. Questi elementi costituiscono una classe di equivalenza. All'interno di un'espressione tra parentesi quadre, per fare riferimento a un elemento qualunque di una certa classe di equivalenza, basta indicare uno di questi tra i delimitatori [= e =]. Per esempio, se si suppone che le lettere e, è ed é, appartengono alla stessa classe di equivalenza, per indicare indifferentemente una di queste, basta la notazione [=e=].

Per indicare effettivamente una classe di equivalenza in un'espressione regolare, occorre ricordare che questa va inserita all'interno di un'espressione tra parentesi quadre. In pratica, l'espressione regolare che corrisponde indifferentemente alla stringa e, è o é, è [[=e=]]. Si osservi che in alternativa si poteva scrivere anche [eèé].

2.4.3   Corrispondenza con una classe di caratteri

Nell'ambito della localizzazione, sono definiti alcuni gruppi di caratteri, attraverso l'uso di parole chiave standard. Per esempio: alpha definisce l'insieme delle lettere alfabetiche; digit definisce l'insieme delle cifre numeriche; space definisce l'insieme dei caratteri che visivamente si traducono in uno spazio di qualche tipo. Oltre a queste, sono definiti dei raggruppamenti, come nel caso di alnum che indica l'insieme di alpha e digit.

All'interno di un'espressione tra parentesi quadre, per indicare una classe di caratteri, si usa il nome riconosciuto dalla localizzazione, racchiuso tra i delimitatori [: e :]. Per esempio, per ottenere la corrispondenza con una sottostringa del tipo file n, dove  n  può essere una cifra numerica qualunque, si può utilizzare l'espressione regolare file[[:digit:]].

La tabella 2.1 riepiloga i nomi delle classi di caratteri riconosciuti normalmente dalle localizzazioni (si veda anche la pagina di manuale locale(5)).

Classe di caratteri Descrizione
upper Collezione alfabetica delle lettere maiuscole.
lower Collezione alfabetica delle lettere minuscole.
alpha Lettere alfabetiche: di solito l'unione di upper e lower.
digit Cifre numeriche.
alnum Cifre alfanumeriche: di solito l'unione di alpha e digit.
punct I caratteri di punteggiatura.
space I caratteri definiti come «spazi bianchi» per qualche motivo.
blank Di solito comprende solo <space> e <tab>.
cntrl I caratteri di controllo che non possono essere rappresentati.
graph Caratteri grafici: di solito l'unione di alnum e punct.
print Caratteri stampabili: di solito l'insieme di alnum, punct e di <space>.
xdigit Cifre numeriche e alfabetiche per rappresentare numeri esadecimali.

Tabella 2.1. Elenco dei nomi standard attribuiti alle classi di caratteri.

2.4.4   Intervalli di caratteri

All'interno di un'espressione tra parentesi quadre, possono apparire anche degli intervalli di caratteri, includendo eventualmente anche gli elementi di collazione. Al contrario, non si possono usare le classi di equivalenza e nemmeno le classi di caratteri per indicare degli intervalli, perché non si traducono in un carattere preciso nell'ambito della codifica. La forma per esprimere un intervallo è la seguente:

inizio - fine

Questo lascia intendere che il trattino (-) abbia un significato particolare all'interno di un'espressione tra parentesi quadre. Per fare un esempio molto semplice, l'espressione regolare [a-d] rappresenta un carattere compreso tra a e d, in base alla localizzazione.

Gli intervalli si possono mescolare con gli elenchi e anche con altri intervalli. Per esempio, l'espressione regolare [a-dhi] individua un carattere compreso tra a e d, oppure anche h o i.

Possono essere aggregati più elenchi assieme, ma tutti questi devono avere un inizio e una fine indipendente. Per esempio, l'espressione regolare [a-cg-z] rappresenta due intervalli, rispettivamente tra a e c, e tra g e z. Al contrario, l'espressione regolare [a-c-z] indica l'intervallo da a a c, oppure il trattino (perché è fuori dal contesto previsto per indicare un intervallo), oppure z.

Quando si indicano degli intervalli non tanto «ovvi», occorre prestare attenzione alla localizzazione per sapere esattamente cosa viene coinvolto. In generale, per questo motivo, le espressioni regolari che contengono espressioni tra parentesi quadre con l'indicazioni di intervalli, non sono portabili da un sistema all'altro.

2.4.5   Protezione all'interno di espressioni tra parentesi quadre

Dal momento che in un'espressione tra parentesi quadre i caratteri ^, - e ], hanno un significato speciale, per poterli utilizzare, occorrono degli accorgimenti: se si vuole usare l'accento circonflesso in modo letterale, è necessario che questo non sia il primo; per indicare il trattino si può descrivere un intervallo, in cui sia posto come carattere iniziale o finale. In alternativa, i caratteri che non si riescono a indicare (come le parentesi quadre), possono essere racchiuse attraverso i delimitatori dei simboli di collazione: [.[.] e [.].] per le parentesi e [.-.] per un trattino.

All'interno di un'espressione tra parentesi quadre, i caratteri che sono speciali al di fuori di questo contesto, qui perdono il loro significato particolare (come nel caso del punto e dell'asterisco (*), oppure ne acquistano uno nuovo (come nel caso dell'accento circonflesso).

2.5   Precedenze

Dopo la difficoltà che si affronta per comprendere il funzionamento delle espressioni regolari, l'ordine in cui le varie parti di queste vengono risolte, dovrebbe essere abbastanza intuitivo. La tabella 2.2 riassume questa sequenza, distinguendo tra espressioni BRE e ERE.

Tipo di componente l' espressione Operatore BRE Operatore ERE
Contenuto delle espressioni tra parentesi quadre. [==] [::] [..] [==] [::] [..]
Caratteri speciali resi letterali. \ carattere_speciale\ carattere_speciale
Espressioni tra parentesi quadre. [] []
Sottoespressioni e riferimenti all'indietro (BRE). \(\) \ n
Raggruppamenti (ERE). ()
Ripetizioni. * \{ m , n \} * + ? { m , n }
Concatenamento di espressioni (non si usano simboli).
Ancore iniziali e finali. ^ $ ^ $
Alternanza (solo ERE). |

Tabella 2.2. Ordine di precedenza, dal più alto al più basso.

2.6   Riferimenti

Informatica per il commercio elettronico 2000.11.04 --- Copyright © 2000 Daniele Giacomini --  daniele @ swlibero.org

Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome espressioni_regolari_standard.html

[successivo] [precedente] [inizio] [fine] [indice generale] [indice analitico]