Sintassi delle espressioni regolari

Sintassi delle espressioni regolari -- Descrizione della sintassi utilizzata da PCRE per la definizione delle espressioni regolari

Descrizione

La libreria PCRE è costituita da una serie di funzioni che utilizzano come criterio di riconoscimento le espressioni regolari mutuando la stessa sintassi e la stessa semantica di Perl 5, a parte qualche lieve differenza descritta di seguito. L'attuale implementazione corrisponde alla versione 5.005 di Perl.

Differenze rispetto a Perl

In questo capitolo saranno descritte le differenze rispetto a Perl 5.005.

  1. Per default, lo spazio bianco indica tutti i caratteri riconoscibili dalla funzione isspace() della libreria C, ciò non pregiudica la possibilità di compilare PCRE con un set di caratteri alternativi. Normalmente isspace() riconosce gli spazi, il salto pagina, il carattere 'a capo' (newline), il carattere carriage return, la tabulazione orizzontale e verticale. Perl 5 non riconosce nel set dei caratteri indicati dallo "spazio bianco" la tabulazione verticale. Infatti il carattere di escape \v è stato presente per diverso tempo nella documentazione di Perl, ma di fatto non viene riconosciuto. Tuttavia lo stesso carattere viene trattato come spazio bianco fino alla versione 5.002 di Perl. Nelle versioni 5.004 e 5.005 non viene riconosciuto il carattere \s.

  2. PCRE non supporta occorrenze ripetute in espressioni che "guardano avanti". Perl lo permette, ma non nel modo a cui si possa pensare. Ad esempio, (?!a){3}, non indica che i tre caratteri successivi non debbano essere delle "a", ma indica per tre volte che il carattere successivo non debba essere una "a".

  3. Il riconoscimento di criteri parziali che possono verificarsi all'interno di espressioni che "guardano avanti" negative sono contati, ma i loro riferimenti non sono inseriti nel vettore degli offset. Perl valorizza le sue variabili da qualsiasi criterio che sia riconosciuto prima che l'espressione regolare fallisca nel riconoscere qualcosa, ma questo solo se l'espressione che "guarda avanti" contiene almeno un ramo alternativo.

  4. Sebbene il carattere di 0 binario sia supportato nella stringa in cui si deve svolgere la ricerca, non è ammesso nel testo dell'espressione regolare, questo perché il testo viene passato come stringa C conclusa dal carattere zero. Si può comunque utilizzare la sequenza "\\x00" per richiedere il riconoscimento dello zero binario.

  5. Non sono supportate le seguenti sequenze di escape di Perl: \l, \u, \L, \U, \E e \Q. Infatti queste sono implementate nelle funzioni di gestione delle stringhe di Perl e non nel suo motore di riconoscimento delle espressioni regolari.

  6. L'asserzione di Perl \G non è supportata.

  7. Ovviamente PCRE non supporta il costrutto (?{code}).

  8. Al momento in cui si scrive, in Perl 5.005_02 vi sono alcune particolarità riguardanti la parametrizzazione delle stringhe catturate quando parte del criterio di riconoscimento viene ripetuto. Ad esempio, il riconoscimento di "aba" con il criterio /^(a(b)?)+$/, valorizza $2 con la lettera "b", usando il testo "aabbaa" con il criterio /^(aa(bb)?)+$/ non si ha la valorizzazione di $2. Tuttavia se il criterio di riconoscimento viene variato in /^(aa(b(b))?)+$/, sia $2 che $3 vengono valorizzate. Nelle versione 5.004 di Perl, la variabile $2 viene valorizzata in entrambi i casi, come pure è TRUE in PCRE. Se in futuro Perl cambierà nella gestione anche PCRE potrà cambiare di conseguenza.

  9. Un'altra discrepanza non ancora risolta riguarda il criterio di riconoscimento /^(a)?(?(1)a|b)+$/, che in Perl 5.005_02 riconosce la stringa "a", mentre non accade in PCRE. Tuttavia in entrambi ( Perl e PCRE ) il riconoscimento di "a" con il criterio /^(a)?a/ non valorizza $1.

  10. PCRE prevede alcune estensione alla gestione delle espressioni regolari di Perl:

    1. Sebbene le asserzioni che "guardano indietro" richiedano testi di lunghezza fissa, è ammesso che ciascun ramo alternativo del criterio di ricerca possa intercettare stringhe di lunghezza differente. Al contrario Perl 5.005 richiede che tutte le stringhe abbiamo la stessa lunghezza.

    2. Se viene settato PCRE_DOLLAR_ENDONLY e non viene attivato PCRE_MULTILINE, il meta-carattere $ indica soltanto la fine della stringa.

    3. Se si attiva PCRE_EXTRA, un carattere backslash (\) seguito da una lettera che non abbia un significato speciale genera un errore.

    4. Se si attiva PCRE_UNGREEDY, si inverte la "voracità" delle occorrenze, in modo da non essere voraci per default, ma lo tornano ad essere se seguiti da "?".

Dettagli sulle espressioni regolari

Introduzione

Di seguito verrà descritta la sintassi e la semantica delle espressioni regolari così come sono supportate da PCRE. La descrizione delle espressioni regolari può essere reperita anche nei manuali di Perl e in numerosi altri libri, alcuni dei quali ricchi di esempi. Ad esempio il libro di Jeffrey Friedl intitolato "Mastering Regular Expressions", edito da O'Reilly (ISBN 1-56592-257-3), li tratta in modo dettagliato. Questa descrizione, invece, viene intesa come una documentazione di riferimento. Una espressione regolare è un criterio utilizzato per identificare parti di un testo partendo da sinistra verso destra. La maggior parte delle lettere identifica se stessa nel testo oggetto del riconoscimento. Ad esempio il banale testo La volpe veloce intercetta la parte del testo uguale all'espressione regolare.

Meta-caratteri

La potenza delle espressioni regolari deriva dalla possibilità di inserire criteri alternativi oppure ripetuti. Questi sono codificati nel criterio di ricerca tramite l'uso di meta-caratteri, lettere che non indicano se stesse, ma sono interpretate in modo particolare.

Esistono due differenti set di meta-caratteri: quelli che sono riconosciuti ovunque tranne che all'interno di parentesi quadrate, e quelli che sono riconosciuti all'interno di parentesi quadrate. I meta-caratteri che si usano all'esterno delle parentesi quadrate sono:

\

carattere di escape generico con diversi utilizzi

^

indica l'inizio del testo (o della linea in modalità multi-linea)

$

indica la fine del testo (o della linea in modalità multi-linea)

.

indica qualsiasi carattere tranne "a capo" (per default)

[

carattere di inizio della definizione di classe

]

carattere di fine della definizione di classe

|

inizio di un ramo alternativo

(

inizio di un criterio di riconoscimento parziale

)

fine del criterio di riconoscimento parziale

?

estende il significato di (, oppure 0 o 1 occorrenza, oppure occorrenza minima

*

0 o più occorrenze

+

1 o più occorrenze

{

inizia l'intervallo minimo/massimo di occorrenze

}

termina l'intervallo minimo/massimo di occorrenze

La parte del criterio che si trova tra parentesi quadrate viene detta "classe di caratteri". In una classe di caratteri i meta-caratteri previsti sono:

\

carattere di escape generico con diversi utilizzi

^

nega la classe, ma solo se posto all'inizio

-

indica un intervallo

]

chiude la classe di caratteri

Le sezioni seguenti descriveranno l'uso di ciascuno dei meta-caratteri.

Backslash

Il carattere backslash (\) ha diversi utilizzi. Primo uso: se viene anteposto a caratteri non alfanumerici, rimuove gli eventuali significati speciali che il carattere può avere. Questo utilizzo di backslash come carattere di escape può essere svolto sia all'interno delle classi di caratteri sia all'esterno.

Ad esempio, un criterio che deve riconoscere il carattere "*" conterrà "\*". Ciò si applica indipendentemente dal carattere seguente, sia esso interpretabile come meta-carattere o meno. Nel caso in cui un carattere non alfanumerico debba identificare se stesso è opportuno farlo precedere dal "\". In particolare per identificare un backslash occorre scrivere "\\".

Se nel criterio di riconoscimento si specifica l'opzione PCRE_EXTENDED, lo spazio bianco (diversamente da quando si trova all'interno di una classe di caratteri), e i caratteri posti tra "#" e un "a capo" all'esterno di una classe di caratteri sono ignorati. Un backslash può essere usato come escape per inserire uno spazio bianco od il carattere "#" come parte del criterio di riconoscimento.

Un secondo utilizzo del backslash consiste nel codificare in modo visibile dei caratteri non visibili. Non ci sono restrizioni nella presenza di caratteri non-stampabili, a parte lo zero binario terminante la stringa dell'espressione regolare. Di seguito saranno elencate le sequenze di caratteri che è preferibile utilizzare per la loro semplicità al posto delle corrispondenti codifiche binarie.

\a

allarme, il carattere BEL (hex 07)

\cx

"control-x", dove x è un qualsiasi carattere

\e

escape (hex 1B)

\f

salto pagina (hex 0C)

\n

"a capo" (newline) (hex 0A)

\r

carriage return (hex 0D)

\t

tabulazione (hex 09)

\xhh

carattere il cui codice esadecimale è hh

\ddd

carattere il cui codice ottale è ddd, oppure riferimento all'indietro

Il preciso effetto di "\cx" è il seguente: se "x" è una lettera minuscola, viene convertita in lettera maiuscola. In pratica viene invertito il sesto bit (hex 40) del carattere. Quindi "\cz" diventa hex 1A, ma "\c{" diventa hex 3B, mentre "\c;" diventa hex 7B.

Dopo la sequenza "\x", saranno letti due numeri esadecimali (per le lettere non si distingue tra maiuscolo e minuscolo)

Dopo la sequenza "\0" saranno lette due cifre in ottale. In entrambi i casi se vi sono meno di due cifre, saranno usati i numeri presenti. Pertanto la sequenza "\0\x\07" indica 2 zeri binari seguiti dal carattere BEL. Occorre accertarsi di passare le cifre necessarie dopo lo zero iniziale se il carattere che segue può essere scambiato per una cifra in ottale.

Più complicata è la gestione del backslash seguito da una cifra diversa da 0. Al di fuori di una classe di caratteri, PCRE tratta le cifre che trova come numeri decimali. Se il numero è inferiore a 10, oppure vi sono state almeno altrettante parentesi sinistre, la sequenza viene considerata come un riferimento all'indietro. Più avanti, nella parte dei criteri parziali, sarà descritto come funzionano questi riferimenti.

All'interno di una classe di caratteri, oppure nel caso in cui il numero decimale è maggiore di 9 e non ci sono stati altrettanti criteri parziali, PCRE rilegge le prime 3 cifre seguenti il backslash in ottale e genera il carattere dagli 8 bit meno significativi del valore ottenuto. Ogni altra cifra seguente indica se stessa. Ad esempio:

\040

è un'altro modo per indicare uno spazio

\40

ha il medesimo significato dell'esempio precedente che non vi sono 40 sotto-criteri

\7

è sempre un riferimento all'indietro

\11

può essere un riferimento all'indietro o un'altro modo per indicare il carattere di tabulazione

\011

è ancora il carattere di tabulazione

\0113

il carattere di tabulazione seguito da "3"

\113

è il carattere con il codice ottale 113 (poiché non ci possono essere più di 99 riferimenti all'indietro)

\377

è un byte con tutti i bit a 1

\81

può essere un riferimento all'indietro o uno zero binario seguito da "8" e da "1"

Occorre rilevare che valori ottali maggiori di 100 non devono essere preceduti dallo zero, questo perché la libreria considera solo tre cifre.

Tutte le sequenze che definiscono il valore di un singolo byte possono essere utilizzate sia all'interno sia all'esterno delle classe di caratteri. Inoltre, all'interno delle classi di caratteri, la sequenza "\b" viene interpretata come carattere di backspace (hex 08), mentre all'esterno ha un'altro significato (come descritto più avanti).

Il terzo utilizzo possibile per il backslash consiste nello specificare il tipo di carattere:

\d

qualsiasi cifra decimale

\D

qualsiasi carattere che non sia una cifra decimale

\s

qualsiasi carattere identificato come spazio bianco

\S

qualsiasi carattere che non sia identificato come spazio bianco

\w

qualsiasi carattere che sia una "parola" (word)

\W

qualsiasi carattere che non sia una "parola" (word)

Ciascuna coppia di sequenze di escape suddivide il set completo dei caratteri in due insiemi disgiunti. Un dato carattere deve essere identificato da un solo insieme di ciascuna coppia.

I caratteri definiti "parole" sono quelle lettere o cifre o il carattere underscore (_), cioè qualsiasi carattere che possa essere parte di una "parola" in Perl. In PCRE le definizioni di lettere e cifre vengono gestite tramite le tabelle dei caratteri, che possono variare in base a specifici parametri di localizzazione (vedere il paragrafo intitolato "Supporto alle localizzazioni"). Ad esempio, nella localizzazione fr (relativa alla Francia), qualche codice carattere maggiore di 128 è utilizzato per le lettere accentate, e queste sono identificate tramite la sequenza \w.

Queste sequenze di tipi di caratteri possono apparire sia all'interno sia all'esterno delle classi di caratteri. Ciascuna di esse identifica un carattere del tipo appropriato. Se durante la fase di identificazione di un testo, si giunge al termine della stringa in cui si esegue il riconoscimento e si hanno ancora di queste sequenze da incrociare, l'operazione di identificazione fallirà perché, ovviamente, non vi sono più caratteri in cui riconoscere le suddette sequenze.

Il quarto utilizzo per il backslash riguarda la costruzione di particolari asserzioni. L'asserzione è una condizione che deve essere soddisfatta ad un certo punto del riconoscimento, senza "consumare" caratteri dalla stringa oggetto del riconoscimento. Più avanti verranno descritte asserzioni più complicate, costruite tramite l'uso di sotto-criteri di riconoscimento, per ora saranno illustrate delle semplici asserzioni costruite con il backslash:

\b

limite di una parola

\B

non limite di una parola

\A

inizio dell'oggetto di ricerca (a prescindere dalla modalità multi-linea)

\Z

fine dell'oggetto di ricerca oppure newline alla fine (a prescindere dalla modalità multi-linea)

\z

fine dell'oggetto di ricerca (a prescindere dalla modalità multi-linea)

Queste asserzioni non possono apparire all'interno di una classe di caratteri (attenzione che la sequenza "\b" all'interno di una classe di caratteri indica il carattere backspace).

Viene definito limite di una parola la posizione nella stringa oggetto della ricerca, nella quale il carattere corrente ed il carattere precedente non soddisfano la sequenza \w o la sequenza \W (ad esempio uno soddisfa la sequenza \w e l'altro carattere soddisfa la sequenza \W), oppure quella posizione, all'inizio o alla fine della stringa, nella quale rispettivamente il primo o l'ultimo carattere soddisfa la sequenza \w.

Le asserzioni \A, \Z e \z differiscono dai tradizionali caratteri "^" e "$" (descritti di seguito) per il fatto di identificare sempre l'inizio o la fine della stringa oggetto di ricerca a prescindere da quale opzione sia stata attivata. Infatti queste asserzioni non sono alterate da PCRE_MULTILINE oppure da PCRE_DOLLAR_ENDONLY. La differenza tra \Z e \z consiste nel fatto che \Z identifica sia il carattere precedente il newline posto al termine della stringa sia la fine della stringa, mentre \z identifica solo la fine.

I caratteri "^" e "$"

In condizioni normali, il carattere "^", posto all'esterno di una classe di caratteri, indica un asserzione che è vera soltanto se il punto da cui si inizia a identificare il testo si trova all'inizio della stringa oggetto della ricerca. Al contrario, se il carattere "^" si trova all'interno di una classe di caratteri, assume altri significati (vedere i capitoli seguenti).

Non è necessario che il carattere "^" sia la prima lettera del criterio di riconoscimento nei casi in cui si utilizzino dei criteri di riconoscimento alternativi. Tuttavia è necessario che sia la prima lettera nei rami alternativi in cui compare. Se si inserisce il carattere "^" in tutte le alternative, caso che ricorre quando si vuole riconoscere un testo a partire dall'inizio della stringa, si dice che si è costruito un criterio di ricerca "ancorato". (Esistono anche altre costruzioni che portano all'ancoraggio di un criterio di ricerca).

Il carattere dollaro "$" è una asserzione che è TRUE soltanto se il punto a cui si è arrivati ad identificare il testo si trova alla fine della stringa oggetto della ricerca, o nella lettera immediatamente precedente il carattere di "a capo", che (per default) è l'ultimo carattere del testo. Il dollaro "$" non deve essere necessariamente l'ultima lettera di un criterio di riconoscimento se in questo si sono utilizzati dei criteri alternativi. Deve, comunque, essere l'ultima lettera nei criteri ove compare. Il carattere dollaro "$" non ha significati speciali all'interno di una classe di caratteri.

Il comportamento del simbolo "$" può essere variato in modo da identificare la reale fine della stringa oggetto di ricerca attivando il flag PCRE_DOLLAR_ENDONLY durante la compila o durante la fase di riconoscimento. Ciò non influisce sull'asserzione \Z.

Il comportamento dei simboli "^" e "$" può essere influenzato dall'opzione PCRE_MULTILINE. Quando viene attivata, questi caratteri identificano rispettivamente, oltre ai tradizionali inizio e fine testo, la lettera immediatamente successiva ed immediatamente precedente il carattere "\n" presente all'interno della stringa oggetto di ricerca. Per esempio il criterio /^abc$/ riconosce il testo "def\nabc" solo in modalità multi-linea. Di conseguenza i criteri di riconoscimento che sono "ancorati" in modalità singola linea, non lo sono in modalità multi-linea. L'opzione PCRE_DOLLAR_ENDONLY viene ignorata se si attiva il flag PCRE_MULTILINE .

Occorre rilevare che le sequenze \A, \Z e \z possono essere utilizzate per riconoscere l'inizio e la fine del testo in entrambe le modalità, e, se tutti i criteri alternativi iniziano con \A, si ha ancora un criterio "ancorato" a prescindere che sia attivata o meno l'opzione PCRE_MULTILINE.

FULL STOP

Il carattere punto ".", all'esterno di una classe di caratteri, identifica qualsiasi carattere, anche quelli non stampabili, ma (per default) non il carattere "a capo". Invece se si abilita l'opzione PCRE_DOTALL si avrà anche il riconoscimento del carattere "a capo". La gestione del simbolo "." è svincolata dalla gestione dei simboli "^" ed "$", l'unica relazione che possono avere riguarda il carattere "a capo". Il punto "." non ha significati speciali all'interno delle classi di caratteri.

Parentesi quadrate

Un parentesi quadrata aperta "[" inizia una classe di caratteri; una parentesi quadrata chiusa "]" termina la definizione della classe. Di suo il carattere di parentesi quadrata chiusa non ha significati speciali. Se occorre inserire la parentesi chiusa all'interno di una classe di caratteri, questa deve essere la prima lettera (ovviamente deve seguire il carattere "^", se presente) oppure deve essere preceduta dal carattere di escape "\".

Una classe di caratteri identifica un singolo carattere nella stringa oggetto di ricerca; il carattere deve comparire nel set di caratteri definito dalla classe, a meno che il primo carattere della classe non sia l'accento circonflesso "^", in tal caso il carattere non deve essere nel set definito dalla classe. Se è richiesto l'inserimento del carattere "^" nel set definito dalla classe, questo non deve essere la prima lettera dopo la parentesi di apertura, oppure deve essere preceduto dal carattere di escape (\).

Ad esempio, la classe [aeiou] identifica ogni vocale minuscola, mentre [^aeiou] identifica tutti i caratteri che non siano delle vocali minuscole. Occorre notare che il simbolo "^" è un modo pratico per indicare i caratteri che sono nella classe, citando quelli che non lo sono. Questa non è una asserzione: consuma un carattere della stringa oggetto di ricerca e fallisce se ci si trova alla fine del testo.

In un riconoscimento senza distinzione tra minuscole e maiuscole, ogni lettera della classe identifica sia la versione maiuscola sia la minuscola. Così, ad esempio, la classe [aeiou] identifica sia "A" sia "a", e, in questo caso, [^aeiou] non identifica "A", mentre con la distinzione delle maiuscole [^aeiou] identifica la lettera "A".

Il carattere di "a capo" (newline) non viene trattato in modo speciale nelle classi di caratteri, indipendentemente dalle opzioni PCRE_DOTALL o PCRE_MULTILINE. La classe [^a] riconosce sempre il carattere "a capo".

Il segno meno (-) può essere usato per definire un intervallo all'interno della classe. Ad esempio, [d-m] identifica ogni lettera compresa tra d ed m inclusi. Se occorre inserire il segno meno (-) come carattere da riconoscere o lo si fa precedere dal carattere di escape (\), oppure lo si mette in una posizione tale che non possa essere identificato come definizione di un intervallo (ad esempio all'inizio o alla fine della definizione della classe).

Non è possibile usare il carattere "]" come limite di un intervallo. Un criterio definito come [W-]46], viene inteso come una classe di due caratteri (W e -) seguita dalla stringa 46], in tal modo sarebbero riconosciuti i testi "W46]" oppure "-46]". Quindi è necessario precedere la lettera "]" con il carattere di escape (\), in questo modo [W-\]46], viene interpretata correttamente come una singola classe contenente un range seguito da due caratteri separati. In alternativa, per delimitare l'intervallo si può utilizzare la notazione ottale di "]".

Gli intervalli utilizzano la sequenza di caratteri ASCII. Inoltre possono essere utilizzati per definire caratteri con specifica numerica (ad esempio [\000-\037]). Nei casi in cui si abiliti il riconoscimento senza distinzione tra lettere maiuscole e minuscole, gli intervalli comprendenti lettere identificano sia la lettera maiuscola che minuscola. Ad esempio, [W-c] è equivalente ad [][\^_`wxyzabc] (con il riconoscimento a prescindere dalla lettera maiuscole e minuscole), e, se si utilizza la tabella dei caratteri locali francesi "fr", [\xc8-\xcb] identifica la lettera "e" accentata sia maiuscola sia minuscola.

Nelle classi di caratteri si possono utilizzare le sequenze \d, \D, \s, \S, \w e \W per aggiungere altri tipi di caratteri alla classe. Ad esempio, [\dABCDEF] riconosce qualsiasi cifra esadecimale. Il carattere "^" può essere utilizzato con i caratteri maiuscoli per indicare un set di caratteri più ristretto che l'identificazione del set di caratteri minuscoli. Ad esempio, la classe [^\W_] identifica qualsiasi lettera o cifra ma non il trattino basso (_).

Tutti i caratteri non alfabetici, eccetto \, -, ^ (posto all'inizio) e ] non sono speciali per la classi di caratteri, e non sono dannosi se preceduti dal caratteri di escape (\).

Barra verticale (|)

La barra verticale (|) viene utilizzata per separare criteri di riconoscimento alternativi. Ad esempio il seguente criterio gilbert|sullivan può riconoscere "gilbert" oppure "sullivan". Ci possono essere innumerevoli alternative, compresa un'alternativa vuota (per identificare una stringa vuota). Il processo di riconoscimento prova tutte le alternative possibili (da sinistra a destra) fino a quando non ne trova una che sia soddisfatta. Se le alternative sono nella definizione di un criterio parziale il riconoscimento ha successo quando avviene su tutto il criterio.

Settaggio delle opzioni interne

Le opzioni PCRE_CASELESS, PCRE_MULTILINE , PCRE_DOTALL e PCRE_EXTENDED possono essere cambiate "al volo" dall'interno del criterio di riconoscimento, utilizzando le sequenze di lettere definite per queste opzioni in Perl, racchiuse tra "(?" ed ")". Le lettere utilizzabili sono:

Tabella 1. Lettere per le opzioni interne

i per PCRE_CASELESS
mper PCRE_MULTILINE
sper PCRE_DOTALL
xper PCRE_EXTENDED

Ad esempio, (?im) abilita il riconoscimento senza distinzione tra lettere maiuscole e minuscole e la modalità multi-linea. E' anche possibile disabilitare queste opzioni facendo precedere la lettera dal segno meno (-), o combinare l'attivazione con la disattivazione come nel caso (?im-sx), in cui si attiva PCRE_CASELESS e PCRE_MULTILINE e si disattiva PCRE_DOTALL e PCRE_EXTENDED. Se la lettera compare sia prima che dopo il segno meno (-) l'opzione resta disabilitata.

L'ambito di validità delle opzioni dipende da dove sono i flag di abilitazione/disabilitazione nel criterio di ricerca. Nei casi in cui il settaggio di un'opzione avvenga all'esterno di un qualsiasi criterio parziale (come definito in seguito) gli effetti sono medesimi di quando l'attivazione/disattivazione avviene all'inizio del criterio di riconoscimento. Gli esempi seguenti si comportano tutti allo stesso modo:


       (?i)abc
       a(?i)bc
       ab(?i)c
       abc(?i)
     

In questi esempi si attiva PCRE_CASELESS per il criterio "abc". In altre parole, questo settaggio compiuto al primo livello si applica a tutto il criterio (a meno che non vi siano altre variazioni nelle sotto-regole di riconoscimento). Qualora vi siano più settaggi per lo stesso parametro, viene utilizzato quello più a destra.

Se si inserisce la variazione di un'opzione in una sotto-regola gli effetti sono differenti. Questa è una variazione rispetto al comportamento di Perl 5.005. Una variazione apportata all'interno di una sotto-regola, vale solo per la parte della sotto-regola che segue la variazione, pertanto (a(?i)b)c identifica abc, aBc e nessuna altra stringa ( si assume che PCRE_CASELESS non sia usato). Da ciò deriva che le opzioni possono avere comportamenti differenti nelle varie parti del criterio di riconoscimento. Ogni variazione apportata ad una ramo alternativo del criterio viene estesa alle alternative successive della medesima sotto-regola. Ad esempio, (a(?i)b|c) identifica "ab", "aB", "c" e "C", anche se per identificare "C" viene scartato il primo ramo prima di incontrare il settaggio dell'opzione. Questo accade perché gli effetti dei settaggi vengono inseriti nella fase di compila. Diversamente si avrebbero dei comportamenti molto bizzarri.

Le opzioni specifiche di PCRE PCRE_UNGREEDY e PCRE_EXTRA possono essere variate nel medesimo modo delle opzioni Perl compatibili, utilizzando rispettivamente i caratteri U e X. Il flag (?X) è particolare poiché deve comparire prima di qualsiasi opzione esso attivi anche quando si trova al primo livello. E' opportuno inserirlo all'inizio.

Sotto-regole

Le sotto-regole sono delimitate dalle parentesi tonde e possono essere annidate. La definizione di una parte di una regola di riconoscimento come sotto-regola può servire a:

1. Localizzare un set di alternative. Ad esempio nel seguente criterio di riconoscimento cat(aract|erpillar|) si riconosce una tra le parole "cat", "cataract" oppure "caterpil- lar". Se non fossero state usate le parentesi, il criterio avrebbe permesso il riconoscimento delle parole "cataract", "erpillar" oppure una stringa vuota.

2. Identificare e catturare parte del testo riconosciuto dalla sotto-regola (come illustrato in seguito). Quando il riconoscimento dell'intero criterio ha avuto successo, le porzioni della stringa oggetto della ricerca identificate dalle sotto-regole sono restituite alla funzione chiamante tramite l'argomento vettore della funzione pcre_exec(). Per determinare il numero ordinale di ciascuna sotto-regola si contano le parentesi aperte da sinistra verso destra partendo da 1.

Ad esempio, se si esegue un riconoscimento nella frase "the red king" con il seguente criterio the ((red|white) (king|queen)) si ottengono i testi "red king", "red" e "king", rispettivamente identificati dalla sotto-regola 1, 2 e 3.

Il fatto che le parentesi tonde adempiano a due funzioni non sempre porta a situazioni comprensibili. Spesso capita di dovere raggruppare delle sotto-regole senza per questo essere richiesta la cattura del testo. A tale scopo l'uso della sequenza "?:" dopo la parentesi di apertura permette di indicare che questa sotto-regola non deve catturare il testo, e non deve essere conteggiata nel numero d'ordine delle sotto-regole di cattura. Ad esempio, applicando il criterio the ((?:red|white) (king|queen)) alla frase "the white queen", si catturano i testi "white queen" e "queen", rispettivamente numerati 1 e 2. Il numero massimo di testi catturabili è 99, il numero massimo di sotto-regole, a prescindere che siano di cattura o meno, è 200.

Come utile abbreviazione, nei casi in cui l'attivazione di alcune opzioni debba essere fatta all'inizio di una sotto-regola non di cattura, la lettera dell'opzione può comparire tra la "?" e ":". Pertanto i due criteri


       (?i:saturday|sunday)
       (?:(?i)saturday|sunday)
    

riconoscono esattamente lo stesso set di parole. Poiché i rami alternativi sono provati da sinistra verso destra, e le opzioni non sono azzerate fino a quando non si è conclusa la sotto-regola, una opzione attivata in un ramo alternativo si applica a tutte le alternative che seguono. Pertanto, nell'esempio di prima, sia la parola "SUNDAY" che la parola "Saturday" sono testi identificati correttamente.

Ripetizioni

Le ripetizioni sono il numero delle occorrenze che possono essere indicate dopo i seguenti elementi:

In generale una occorrenza specifica un numero minimo e massimo di riconoscimenti previsti tramite la specifica dei due limiti, posti tra parentesi graffe e separati da una virgola. Entrambi i numeri devono essere minori di 65536 ed il primo deve essere minore o uguale rispetto al secondo. Ad esempio: z{2,4} identifica "zz", "zzz" oppure "zzzz". La parentesi graffa chiusa di suo non rappresenta un carattere speciale. Se si omette il secondo numero, ma si lascia la virgola, non si indica un limite superiore; se sia la virgola sia il secondo numero sono omessi, l'occorrenza specifica l'esatto numero di riconoscimenti richiesti. Il criterio [aeiou]{3,} identifica almeno 3 o più vocali consecutive, mentre \d{8} identifica esattamente 8 cifre. Una parentesi graffa aperta che compaia in una posizione in cui non sia prevista una occorrenza, o che comunque non sia riconducibile alla sintassi di una occorrenza, viene tratta come il carattere "{". Ad esempio {,6} non indica delle occorrenze, ma una stringa di 4 caratteri.

L'indicazione {0} è permessa. Indica di comportarsi come se l'elemento precedente all'occorrenza non fosse presente.

Per praticità (e compatibilità verso il passato) si usano 3 abbreviazioni per le occorrenze più comuni:

Tabella 2. Indicatore di occorrenza

*equivale a {0,}
+equivale a {1,}
?equivale a {0,1}

E' anche possibile creare un ciclo infinito facendo seguire ad una sotto-regola che non identifica alcun carattere una occorrenza priva di limite superiore. Ad esempio: (a?)*

Le versioni precedenti di Perl e di PCRE segnalavano un errore durante la fase di compila per questi criteri. Tuttavia, poiché vi sono casi dove questi criteri possono essere utili, queste regole sono accettate, ma, se la ripetizione non riconosce alcun carattere, il ciclo viene interrotto.

Per default le occorrenze sono "bramose", infatti identificano più testi possibile (fino al numero massimo permesso), senza per questo fare fallire il riconoscimento della parte rimanente del criterio di ricerca. Il classico esempio dove questo comportamento può essere un problema, riguarda il riconoscimento dei commenti nei programmi C. Questi compaiono tra le sequenze /* ed */, ma all'interno, nel commento, si possono usare sia il carattere *, sia il carattere /. Il tentativo di individuare i commenti C con il seguente criterio /\*.*\*/ se applicato al commento /* primo commento */ nessun commento /* secondo commento */ non ha successo, perché identifica l'intera stringa a causa della "bramosia" dell'elemento ".*".

Tuttavia, se un'occorrenza è seguita da un punto interrogativo, questa cessa di essere "bramosa", e identifica il numero minimo di testi permessi. Pertanto il criterio /\*.*?\*/ si comporta correttamente con i commenti C. Il significato delle varie occorrenze non è stato cambiato, si è soltanto modificato il numero delle occorrenze da riconoscere. Attenzione a non confondere questo uso del punto interrogativo con il suo proprio significato. Dati i due utilizzi del ?, può anche capitare di averli entrambi come in \d??\d che, preferibilmente, identifica una cifra, ma può riconoscerne due se questa è l'unica via per soddisfare il riconoscimento dell'intero criterio.

Se si attiva l'opzione PCRE_UNGREEDY (un'opzione disponibile anche in Perl), per default le occorrenze non sono "bramose", ma ogni singola occorrenza può essere resa "bramosa" se seguita dal punto interrogativo. In altre parole si è invertito il normale comportamento.

Quando si indica un numero minimo di occorrenze maggiore di 1, per una sotto-regola posta tra parentesi, oppure si indica un numero massimo di occorrenze, la fase di compila richiede più spazio in proporzione ai valori minimo e massimo.

Se un criterio inizia con .* oppure .{0,} e si è attivata l'opzione PCRE_DOTALL (equivalente al /s di Perl), permettendo al . di identificare il carattere di "a capo", si dice che il criterio è implicitamente ancorato, perché qualsiasi elemento che segue sarà confrontato con ciascun carattere della stringa oggetto della ricerca, e pertanto non vi è nessuna posizione, a parte la prima, da cui ripartire per ritentare il riconoscimento dell'intero criterio. PCRE tratta tale criterio come se fosse preceduto dalla sequenza \A. Nei casi in cui è noto a priori che la stringa oggetto di ricerca non contiene caratteri di "a capo", vale la pena di attivare l'opzione PCRE_DOTALL se il criterio di ricerca inizia con ".*", per ottenere questa ottimizzazione, oppure, in alternativa, usare "^" per indicare in modo esplicito un ancoraggio.

Quando si ripete una sotto-regola di cattura, il testo estrapolato è la parte identificata dall'iterazione finale. Ad esempio se il criterio (tweedle[dume]{3}\s*)+ viene applicato al testo "tweedledum tweedledee", il testo estrapolato sarà "tweedledee". Tuttavia se vi sono delle sotto-regole annidate, il testo catturato può essere determinato dalle iterazioni precedenti. Ad esempio nel criterio /(a|(b))+/ applicato a "aba", la seconda stringa catturata è "b".

Riferimenti all'indietro

Esternamente ad una classe di caratteri, un backslah (\) seguito da una o più cifre maggiori di 0 è un riferimento all'indietro verso testi catturati precedentemente (ad esempio alla sinistra rispetto a dove ci si trova), conteggiati tramite il numero delle parentesi chiuse precedenti.

Tuttavia, se il numero che segue il backslash (\) è un valore inferiore a 10, si assume che si tratti sempre di un riferimento all'indietro, e pertanto viene generato un errore se nel criterio non vi sono almeno altrettante parentesi chiuse di sotto-regole di cattura. In altre parole per i numeri inferiori a 10 non è necessario che il numero parentesi precedenti (a sinistra) alla sotto-regola sia pari o maggiore al numero indicato. Vedere la sezione relativa al backslash per informazioni su come gestire le cifre seguenti il backslash.

Un riferimento all'indietro identifica ciò che è già stato catturato dalla sotto-regola, e non ciò che la sotto-regola stessa possa riconoscere. Ad esempio il criterio (sens|respons)e and \1ibility può riconoscere "sense and sensibility" oppure "response and responsibility", ma non il testo "sense and responsibility". Se al momento del riferimento all'indietro, è attiva la distinzione tra lettere maiuscole e minuscole, il formato della lettera diventa rilevante. Ad esempio, ((?i)rah)\s+\1 può identificare "rah rah" e "RAH RAH", ma non "RAH rah", anche se la sotto-regola originale eseguiva dei riconoscimenti a prescindere dalle lettere maiuscole e minuscole.

Nella medesima sotto-regola si possono avere più di un riferimento all'indietro. Se una sotto-regola non viene utilizzata in un particolare riconoscimento, un riferimento a questa ha sempre esito negativo. Ad esempio il criterio (a|(bc))\2 non avrà mai successo se l'identificazione della stringa inizia con "a" e non con "bc". Dato che sono possibili fino a 99 riferimenti all'indietro, tutte le cifre che seguono un backslash (\) sono considerate come parte di un potenziale numero di riferimento. Se il criterio continua con altri caratteri numerici, occorre stabilire un carattere per delimitare il numero del riferimento. Se si attiva l'opzione PCRE_EXTENDED questo carattere può essere lo spazio. Altrimenti si può usare un commento vuoto.

Un riferimento all'indietro non ha successo se viene inserito in una sotto regola prima che sia applicata. Con questo si intende, ad esempio, che (a\1) non avrà mai successo, ma, nel caso di una sottoregola ripetuta, si avrà un riscontro positivo. Ad esempio (a|b\1)+ identificherà qualsiasi numero di "a", ma anche "aba" oppure "ababaa" eccetera. In pratica a ciascuna iterazione della sotto-regola il riferimento andrà a sostituire la stringa riconosciuta tramite la sotto-regola dell'iterazione precedente. Affinchè il tutto funzioni, è necessario che la prima iterazione sia identificata senza l'ausilio del riferimento "all'indietro". Ciò può essere ottenuto o usando casi alternativi, come nell'esempio precedente, o usando le occorrenze indicando come numero minimo di occorrenze il valore zero.

Asserzioni

L'asserzione è un test basato su un carattere, che può precedere o seguire l'attuale punto di riconoscimento, e non consuma alcun carattere. Le semplici asserzioni quali \b, \B, \A, \Z, \z, ^ e $ sono state descritte precedentemente. Asserzioni più complesse possono essere strutturate come delle sotto-regole. Se ne hanno di due tipologie: quelle che "guardano avanti" alla posizione attuale nella stringa oggetto del riconoscimento, e quelle che "guardano dietro" la posizione attuale.

Una asserzione definita come sotto-regola esegue il riconoscimento nel modo usuale, ma tale riconoscimento non sposta la posizione attuale nella stringa. Le asserzioni che "guardano avanti" cominciano per "(?=", se sono positive, per "(?!", se sono asserzioni negative. Ad esempio \w+(?=;) riconosce una parola seguita da ";", ma non include il punto e virgola nel riconoscimento, mentre foo(?!bar) identifica qualsiasi occorrenza di "foo" che non sia seguita da "bar". Attenzione che il criterio, apparentemente simile, (?!foo)bar non riconosce alcuna occorrenza di "bar" se questa è preceduta da qualsiasi testo che non sia "foo"; infatti l'espressione riconosce qualsiasi occorrenza di "bar", poiché l'asserzione (?!foo) è sempre TRUE quando i tre caratteri successivi sono "bar". Pertanto è necessario una asserzione che "guarda" all'indietro per ottenere effetto desiderato.

Le asserzioni che "guardano" indietro positive iniziano con "(?<=", e con "(?<!" le negative. Ad esempio: (?<!foo)bar riconosce una occorrenza di "bar" che non sia preceduta da "foo". Le asserzioni che "guardano" indietro hanno una limitazione: tutte le stringhe che riconoscono devono avere lunghezza fissa. Mentre, se si hanno casi alternativi, la limitazione della lunghezza fissa non sussiste. Quindi (?<=bullock|donkey) è una asserzione permessa, ma (?<!dogs?|cats?) genera un errore durante la fase di compila. Rami alternativi con lunghezze di stringa differenti sono permessi solo al primo livello dell'asserzione. Questa è da considerarsi una estensione rispetto a Perl 5.005, che richiede a tutte le alternative possibili la medesima lunghezza di stringa. Quindi una asserzione tipo (?<=ab(c|de)) non è permessa, poiché il suo singolo ramo di primo livello può identificare testi di due lunghezze differenti, ma è accettabile se riscritta usando due alternative di primo livello: (?<=abc|abde) L'implementazione di questo tipo di asserzioni consiste, per ciascuna alternativa, di uno spostamento all'indietro temporaneo per la lunghezza fissa necessaria, e ad un tentativo di riconoscimento del testo. Se non ci sono sufficienti caratteri precedenti alla posizione attuale, l'asserzione è destinata a fallire. L'uso accoppiato delle asserzioni che "guardano" indietro con sotto-regole a riconoscimento singolo può essere utile per identificare la fine dei testi; un esempio è illustrato al termine della sezione sulle sotto-regole a riconoscimento singolo.

Diverse asserzioni (di qualsiasi tipologia) possono essere utilizzate in modo consecutivo. Ad esempio: (?<=\d{3})(?<!999)foo riconosce "foo" preceduto da tre cifre che non siano "999". Occorre rilevare che ciascuna asserzione viene applicata singolarmente sul medesimo punto nella stringa oggetto di riconoscimento. Nell'esempio precedente per prima cosa si verifica che i tre caratteri precedenti siano cifre, quindi che non siamo "999". Questo esempio non identifica il testo se "foo" è preceduto da sei caratteri di cui i primi tre siano cifre e i secondi tre non siano "999". In pratica il testo "123abcfoo" non viene riconosciuto. Un criterio per riconoscere tale stringa può essere: (?<=\d{3}...)(?<!999)foo

In questo caso la prima asserzione controlla i primi sei caratteri verificando che i primi tre siano cifre, mentre la seconda asserzione verifica che i secondi tre caratteri non siano "999".

Le asserzioni possono essere annidate in qualsiasi combinazione. Il seguente esempio (?<=(?<!foo)bar)baz identifica il testo "baz" se è preceduto da "bar" il quale non deve essere preceduto da "foo", mentre (?<=\d{3}(?!999)...)foo è un'altro criterio che riconosce "foo" preceduto da tre cifre e da tre caratteri che non siano "999".

Le asserzioni definite come sotto-regole non catturano parte del testo e non possono essere ripetute (non avrebbe senso ripetere il medesimo riconoscimento sul medesimo testo). Se una di queste asserzioni contiene una sotto-regola di cattura questa viene conteggiata ai fini della numerazione delle regole di cattura. Tuttavia il testo viene effettivamente catturato solo nelle asserzioni positive, dato che non avrebbe senso farlo in quelle negative.

Le asserzioni possono essere composte fino ad un massimo di 200 sotto-regole. subpatterns.

Sotto-regole a riconoscimento singolo (Once-only subpatterns)

Con l'indicazione del numero minimo e massimo di ripetizioni, il fallimento del riconoscimento della parte successiva del testo causa una ripetizione dell'identificazione con un numero di occorrenze diverse per verificare se in questa situazione anche il resto del testo viene identificato. In alcune situazioni può essere utile bloccare questo meccanismo, per la cambiata natura del criterio, oppure per fare fallire la ricerca prima di quando potrebbe accadere, oppure quando l'autore sa che non ci sono punti da cui ripartire.

Consideriamo, ad esempio, il criterio \d+foo applicato alla seguente linea 123456bar

Dopo avere identificato le 6 cifre ed avere mancato nel riconoscimento di "foo", il comportamento normale consiste nel tentare di procedere identificando 5 cifre per l'elemento \d+, quindi tentare con 4 e così via, prima di fallire definitivamente. Le sotto-regole a riconoscimento singolo permettono di specificare che, una volta riconosciuta una porzione della regola, questa non debba essere più considerata, in maniera tale da abortire immediatamente il riconoscimento se non si ha successo nell'identificare la parte restante del criterio. L'espressione per definire questo tipo di sotto-regola richiede un'altro tipologia di utilizzo speciale delle parentesi. Infatti iniziano con (?> come nell'esempio seguente: (?>\d+)bar

Questa tipologia di parentesi "inchioda" la parte di criterio una volta che avviene il riconoscimento, e, quindi, un fallimento successivo impedisce la ri-elaborazione di questo segmento. Tuttavia, occorre notare che gli elementi precedenti a questo si comportano in modo normale, e pertanto la ri-elaborazione, pur non toccando questo elemento, passa ai precedenti.

Una descrizione alternativa di questa tipologia di sotto-regola potrebbe essere che questo criterio identifica un testo come avrebbe fatto un singolo criterio se fosse stato ancorato alla posizione corrente.

Le sotto-regole a riconoscimento singolo non compiono la cattura del testo identificato. I casi semplici illustrati in precedenza possono essere considerati come una estremizzazione della ripetizione che porta ad inglobare tutto ciò che può. Pertanto, da una parte \d+ e \d+? sono sequenze che si adattano a riconoscere il numero corretto di cifre affinchè la ricerca abbia successo, dall'altra la sequenza (?>\d+) riconosce soltanto una sequenza di cifre.

Ovviamente queste costruzioni possono contenere diverse sotto-regole sia complesse, sia annidate.

Le sotto-regole a riconoscimento singolo possono essere usate congiuntamente alle asserzioni che guardano indietro, per definire una regola efficiente per riconoscere la fine della stringa. Ad esempio si consideri questo semplice criterio: abcd$ quando viene applicato ad un lungo testo può non avere successo. Questo perché il riconoscimento procede da sinistra verso destra, quindi PCRE prima cerca la "a", e poi cerca di riconoscere la parte restante del criterio. Se si modifica il criterio nel seguente modo ^.*abcd$ allora la sequenza iniziale .* in prima battuta identificherà tutto il testo, ma quando fallisce (poiché non vi sono più "a"), la ricerca tornerà indietro di uno (quindi tutto il testo tranne l'ultimo carattere), quindi, se continua non esserci la "a", si torna indietro di due, e così via. Continuando a tornare indietro alla ricerca della "a" si percorre tutto il testo da destra a sinistra, senza ottenere nulla di valido. Tuttavia se si riscrive il criterio come: ^(?>.*)(?<=abcd) non si attiva più lo scorrimento verso sinistra per .* , ma viene costretto a riconoscere tutto il testo (esito del primo tentativo). La asserzione successiva, esegue una verifica sulle ultime 4 lettere.Se fallisce, ciò avviene immediatamente, provocando un impatto sensibile nei tempi di elaborazione con testi molto lunghi.

Quando un criterio di riconoscimento contiene un elemento ripetuto senza limite all'interno di una sotto-regola che anch'essa possa ripetuta illimitatamente, l'uso delle sotto-regole a riconoscimento singolo è l'unico mezzo per evitare che certi mancati riconoscimenti richiedano molto tempo per essere rilevati. Ad esempio il criterio (\D+|<\d+>)*[!?] riconosce un numero indefinito di frammenti di testo contenenti a loro volta numeri o caratteri non numerici racchiusi tra <>, seguiti dai caratteri ! o ?. Quando il riconoscimento ha successo l'esecuzione è rapida, ma quando viene applicato al testo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa richiede molto tempo prima di evidenziare l'errore. Questo accade perché la stringa può essere suddivisa tra i due elementi ripetuti in un elevato numero di modi che debbono essere verificati. Nell'esempio si usa [!?] piuttosto che un singolo carattere alla fine, questo perché sia Perl sia PCRE hanno una ottimizzazione che permette un veloce riconoscimento dell'errore se si usa un solo carattere. Infatti memorizzano l'ultimo carattere singolo richiesto per un riconoscimento, e, se non lo trovano nel testo, falliscono subito. Se il criterio viene modificato in ((?>\D+)|<\d+>)*[!?] le sequenze di caratteri non numerici non possono essere interrotte e pertanto il mancato riconoscimento viene rilevato più velocemente.

Sotto-regole condizionali (Conditional subpatterns)

E' possibile forzare il processo di riconoscimento a obbedire alle sotto-regole in modo condizionato, oppure a scegliere tra due alternative in base al risultato di una asserzione, o piuttosto se la sotto-regola di cattura precedente ha riconosciuto il proprio testo. I due metodi possibili per esprimere una sotto-regola condizionale sono:


       (?(condizione)yes-pattern)
       (?(condizione)yes-pattern|no-pattern)
    

Se la condizione è soddisfatta, si usa la regola indicata in yes-pattern, altrimenti si applica il no-pattern (qualora sia specificato). Se nella sotto-regola vi sono più di due alternative, PCRE segnala un errore in fase di compila.

Vi sono due tipi di condizioni. Se il testo tra le parentesi consiste in una sequenza di cifre, allora la condizione è soddisfatta se la sotto-regola di cattura di quel numero è stata precedentemente riconosciuta. Si consideri il seguente criterio contenente degli spazi non significativi per renderlo più leggibile (si assuma che sia attiva l'opzione PCRE_EXTENDED) e lo si divida in tre parti per praticità di discussione: ( \( )? [^()]+ (?(1) \) )

La prima parte riconosce una parentesi aperta opzionale, e, se è presente, indica quello come primo segmento di stringa catturato. La seconda parte riconosce uno o più caratteri che non siano parentesi. Infine la terza parte è una sotto-regola condizionale che verifica se la prima parentesi è stata identifica o meno. Se accade, come nel caso in cui il testo inizi con una parentesi aperta, la condizione è TRUE, e quindi viene eseguito il ramo yes-pattern, richiedendo, conseguentemente, la parentesi chiusa. Diversamente, poiché non è specificato ramo no-pattern, non si esegue nessun altro riconoscimento. In altre parole questo criterio identifica un testo che possa essere racchiuso tra parentesi opzionali.

Se la condizione non è una sequenza di cifre, deve essere una asserzione. Questa può essere sia una asserzione che guarda avanti, sia una asserzione cha guarda indietro, sia positiva sia negativa. Si consideri il seguente criterio, ancora una volta contenente spazi non significativi, e con due alternative nella seconda linea:


       (?(?=[^a-z]*[a-z])
       \d{2}-[a-z]{3}-\d{2}  |  \d{2}-\d{2}-\d{2} )
    

La condizione è una asserzione che guarda avanti positiva, la quale identifica una sequenza opzionale di caratteri non alfabetici seguiti da una lettera. In altre parole, si testa la presenza di almeno una lettera nel testo. Se la lettera viene trovata si applica il primo criterio per il riconoscimento del testo, altrimenti viene applicato il secondo criterio. Questo criterio riconosce stringhe in due formati dd-aaa-dd oppure dd-dd-dd, dove aaa sono lettere e dd sono numeri.

Commenti

La sequenza (?# indica l'inizio di un commento che si conclude con la successiva parentesi chiusa. Parentesi annidate non sono permesse. I caratteri che fanno parte di un commento non giocano alcun ruolo nella fase di riconoscimento.

Se viene attivata l'opzione PCRE_EXTENDED, un carattere # privo della sequenza di escape (\) all'esterno di una classe di caratteri apre un commento che continua fino al carattere di "a capo".

Criteri ricorsivi

Si consideri il caso in cui si debba riconoscere una stringa tra parentesi, si supponga inoltre di dovere ammettere un numero arbitrario di parentesi annidate. Senza l'uso della ricorsione, il miglior metodo consiste nel preparare un criterio che identifichi un numero finito di parentesi annidate. Però, in questo modo non si gestisce un numero arbitrario si parentesi annidate. Nella versione 5.6 di Perl è stata introdotta, a livello sperimentale, la possibilità per i criteri di riconoscimento di essere ricorsivi. Allo scopo è stata definita la sequenza speciale (?R). Il criterio illustrato di seguito risolve il problema delle parentesi (si assume che l'opzione PCRE_EXTENDED sia attivata in modo da ignorare gli spazi): \( ( (?>[^()]+) | (?R) )* \)

In principio si identifica la parentesi di apertura. Quindi si cerca un numero indefinito di stringhe che possano essere composte da caratteri che non siano parentesi, oppure che siano riconosciute ricorsivamente dal criterio (ad esempio una stringa correttamente tra parentesi). Infine si cerca la parentesi di chiusura.

In questo particolare esempio si hanno arbitrarie ripetizioni annidate, e quindi l'uso delle sotto-regole a riconoscimento singolo per il riconoscimento della stringa priva di parentesi è particolarmente utile se il criterio viene applicato ad un testo non riconoscibile. Ad esempio, applicando il criterio a (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() si ottiene un esito di mancato riconoscimento rapidamente. Se, al contrario, non si fosse usato il criterio a riconoscimento singolo, sarebbe occorso molto tempo per avere un esito dato che vi sono moltissimi modi in cui i caratteri di ripetizione + e * possono essere applicati al testo, richiedendo, pertanto, la verifica di tutte le combinazioni prima di fornire l'esito negativo.

Il valori restituiti da una sotto-regola di cattura sono quelli ottenuti dal livello di ricorsione più esterno. Se il criterio illustrato in precedenza venisse applicato al testo (ab(cd)ef) Il valore ottenuto sarebbe "ef", che rappresenta l'ultimo valore catturato al livello più alto. Se si aggiungono altre parentesi al criterio, ottenendo \( ( ( (?>[^()]+) | (?R) )* ) \) allora il testo ottenuto sarebbe "ab(cd)ef", cioè il valore delle parentesi di livello più alto. Se nel criterio vi sono più di 15 sotto-regole di cattura, PCRE ha necessità di ottenere maggiore memoria per archiviare le informazioni durante la ricorsione. Questa memoria è ottenuta utilizzando pcre_malloc, al termine verrà liberata con pcre_free. Se non può essere ottenuta ulteriore memoria, si ha il salvataggio delle informazioni dei primi 15 testi catturati, dato che non vi è modo di restituire un messaggio di memoria insufficiente dalla ricorsione.

Performances

Certi elementi utilizzati per i criteri di riconoscimento sono più efficienti di altri. E' più efficiente usare le classi di caratteri come [aeiou] piuttosto che un gruppo di alternative come (a|e|i|o|u). In generale la costruzione più semplice per ottenere un dato scopo è la più efficiente. Nel libro di Jeffrey Friedl sono illustrate varie tecniche sull'ottimizzazione delle espressioni regolari.

Quando un criterio comincia con .* ed è attiva l'opzione PCRE_DOTALL, il criterio è implicitamente ancorato da PCRE, dato che può rico- noscere solo l'inizio della stringa. Tuttavia, se non è attivo PCRE_DOTALL, PCRE non può fare questa ottimizzazione, perché il meta-carattere . non ri- conosce più il carattere di "a capo", e quindi se la stringa contiene dei caratteri di "a capo", il riconoscimento può par- tire dal carattere immediatamente successivo ad uno di questi e non dall'inizio. Ad esempio il criterio (.*) second può eseguire un riconoscimento nel testo "first\nand second" (dove \n indica il carattere "a capo") ottenendo "and" come prima stringa catturata. perché ciò accada è necessario che PCRE possa iniziare il riconoscimento dopo ogni "a capo".

Se si deve usare un simile criterio in stringhe che non conten- gono caratteri di "a capo", le performance migliori si possono ottenere abilitando PCRE_DOTALL, oppure iniziando il criterio con ^.* in modo da richiedere un ancoraggio esplicito. Così si risparmia a PCRE di scandirsi il testo alla ricerca di un "a capo" da cui ripartire per la ri- cerca.

Occorre prestare attenzione ai criteri che contengono ripeti- zioni indefinite annidate. Possono richiedere molto tempo se applicati a stringhe non riconoscibili. Si consideri il fram- mento (a+)*

Questo può riconoscere "aaaa" in 33 modi differenti, e questo numero può crescere molto rapidamente se la stringa da ricono- scere è più lunga. (Il carattere di ripetizione * può eseguire riconoscimenti per 0,1,2,3 o 4 ripetizioni, e per ciascuna di esse, tranne lo 0, il carattere di ripetizione + può esegui- re riconoscimenti per diversi numeri di volte). Quindi se la parte successiva del criterio è tale da non permettere il com- pletamento del riconoscimento, PCRE, per principio, ugualmente tenta tutte le possibili variazioni, richiedendo diverso tempo.

Una ottimizzazione riesce a catturare qualche caso semplice come in (a+)*b dove si indica che seguirà un carattere alfanumerico. PCRE, prima di imbarcarsi nella procedura standard di riconoscimen- to, verifica se nel testo vi è la lettera "b", e se non c'è restituisce immediatamente un esito negativo. Tuttavia se non viene indicata una lettera seguente questa ottimizzazione non può essere utilizzata. Se ne può notare la differenza analiz- zando il comportamento del criterio (a+)*\d rispetto al precedente. Il primo, utilizzato con una stringa composta da "a", fallisce immediatamente, l'ultimo richiede un tempo apprezzabile, soprattutto se applicato a stringhe con più di 20 caratteri.