PHP Conference Nagoya 2025

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 è la stringa (R), è soddisfatta se è stata fatta una chiamata ricorsiva alla regola o sotto-regola. Al "top level", la condizione è falsa.

Se la condizione non è una sequenza di cifre o (R), deve essere una asserzione. Questa può essere un'asserzione in avanti, all'indietro, Rpositiva o 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.

add a note

User Contributed Notes 1 note

up
3
Anonymous
13 years ago
Repetition of a subpattern will repeat conditionals that are contained inside it, updating subpattern matches with iteration.

Consider the following code, which scans thru HTML, keeping track of angle brackets "<" ">". If open bracket "<" matches, then closing bracket ">" must follow before repetition can possibly end. That way regex will effectively match only outside of tags.

<?php
$pattern
='%(*ANY)(.*?(<)(?(2).*?>)(.*?))*?\'\'%s';
$replace='\1Fred';
$subject=
'<html><body class=\'\'>\'\' went to '\'\meyer and ran
into <b>\'\'</b>.
</body></html>'
echo preg_replace("%(*ANY)(.*?((<)(?(3).*?>).*?)*?)\'\'%s",'\1Fred',$subject);
?>

Output will be:
'<html><body class=\'\'>Fred went to Fredmeyer and ran
into <b>Fred</b>.
</body></html>'
To Top