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 CRE_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.
(?1)
, (?2)
e così via
possono pure essere usati per sottoregole ricorsive. È anche possibile usare
sottoregole con nome: (?P>name)
oppure
(?P&name)
.
Se la sintassi di un riferimento a sottoregola (identificata per numero o
per nome) è usata al di fuori delle parentesi a cui si riferisce, si comporta
come una funzione di un linguaggio di programmazione. Un esempio precedente
mostrava come la regola
(sens|respons)e and \1ibility
trova "sense and sensibility" e "response and responsibility", ma
non "sense and responsibility". Se si usa invece la regola
(sens|respons)e and (?1)ibility
,
questa identifica anche "sense and responsibility", come pure le altre
due stringhe. Questi riferimenti devono, comunque, seguire le sottoregole a
cui si riferiscono.
La lunghezza massima di una stringa corrisponde al pìù grande numero
positivo ammesso per una variabile integer. D'altra parte, PCRE usa la ricorsione per
gestire le sottoregole e le ripetizioni indefinite. Questo significa che
lo spazio di stack disponibile può limitare la dimensione di una stringa che può
essere processata da determinate regole.