PHP Conference Nagoya 2025

Sub-patrones condicionales

Es posible hacer que el proceso de comparación obedezca a un sub-patrón condicionalmente o que elija entre dos sub-patrones alternativos, dependiendo del resultado de una declaración o de si un sub-patrón de captura previo coincidió o no. Las dos formas posibles de un sub-patrón condicional son

(?(condición)patrón-sí)
(?(condición)patrón-sí|patrón-no)

Si la condición es satisfecha, se usa el patrón-sí; de otro modo se usa el patrón-no (si está presente). Si hay más de dos alternativas en el sub-patrón, se producirá un error en tiempo de compilación.

Hay dos tipos de condiciones. Si el texto entre los paréntesis consisite en una secuencia de dígitos, la condición es satisfecha si el sub-patrón de captura de ese número ha coincidido anteriormente. Considere el siguiente patrón, el cual contiene espacios en blanco no significativos para hacerlo más legible (se asume la opción PCRE_EXTENDED) y para dividirlo en tres partes para facilitar su análisis:

( \( )?    [^()]+    (?(1) \) )

La primera parte compara un paréntesis de apertura opcional, y si el carácter está presente, lo establece como la primera subcadena capturada. La segunda parte compara uno o más caracteres que no sean paréntesis. La tercera parte es un patrón condicional que examina el primer conjunto de paréntesis coincididos o no. Si lo fueron, es decir, si el sujeto comenzó con un paréntesis de apertura, la condición es true, y así el patrón-sí se ejecuta y es requerido un paréntesis de cierre. De otra manera, ya que el patrón-no no está presente, el subpatrón no coincidirá con nada. En otras palabras, este patrón coincide con una secuencia que no tenga paréntesis, opcionalmente encerrada entre paréntesis.

Si la condición es la cadena (R), se satisface si ha sido hecha una llamada recursiva al patrón o sub-patrón. En el "nivel superior", la condición es falsa.

Si la condición no es una secuencia de dígitos o (R), debe de ser una declaración. Ésta puede ser una declaración de búsqueda hacia delante o hacia atrás, negativa o positiva. Considere este patrón, conteniendo de nuevo espacios en blanco no significativos, y con dos alternativas en la segunda línea:

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

La condición es una declaración de búsqueda hacia delante positiva que compara una secuencia opcional de algo que no sean letras seguida de una letra. En otras palabras, comprueba la presencia de al menos una letra en el sujeto. Si se encuentra una letra, el sujeto se compara con la primera alternativa; de otro modo se compara con la segunda. Este patrón coincide con cadenas en una de las dos formas dd-aaa-dd o dd-dd-dd, donde aaa son letras y dd son dígitos.

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