CakeFest 2024: The Official CakePHP Conference

Retroreferencias

Fuera de una clase carácter, una barra invertida seguida por un dígito mayor que 0 (y posiblemente más dígitos) es una retroreferencia a un sub-patrón de captura anterior (esto es a su izquierda) del patrón, siempre que hayan habido tantas capturas entre paréntesis previas a la izquierda.

Sin embargo, si el número decimal que sigue a la barra invertida es menor que 10, siempre es tomado como una retroreferencia, y produce un error sólo si no hay tantas capturas anteriores entre paréntesis en el patrón completo. En otras palabras, los paréntesis que son referenciados no necesitan estar a la izquierda de la referencia para números menores que 10. Una "retroreferencia hacia adelante" puede tener sentido cuando está involucrada una repetición y el sub-patrón de la derecha ha participado en una iteración anterior. Véase la sección anterior titulada "Barra invertida" para más detalles acerca del manejo de los dígitos que siguen a una barra invertida.

Una retroreferencia coincide con cualquier cosa que en realidad haya coincidido con el sub-patrón de captura en la cadena objetivo actual, más que con cualquier cosa que coincida en el sub-patrón mismo. Así, el patrón (abraz|apreci)o de un \1ador coindice con "abrazo de un abrazador" y con "aprecio de un apreciador", pero no con "abrazo de un apreciador". Si la coincidencia sensible a mayúsculas-minúsculas está en vigor en el momento de la retroreferencia, la distinción de letras es relevante. Por ejemplo, ((?i)bla)\s+\1 coincide con "bla bla" y "BLA BLA", pero no con "BLA bla", incluso si el patrón de captura original es comparado de forma insensible a mayúsculas-minúsculas.

Puede haber más de una retroreferencia hacia el mismo sub-patrón. Si un sub-patrón no ha sido usado en realidad en una coincidencia en particular, cualquier retroreferencia a él siempre falla. Por ejemplo, el patrón (a|(bc))\2 siempre falla si comienza coincidiendo con "a" en vez de con "bc". Ya que puede haber hasta 99 retroreferencias, todos los dígitos que siguen a la barra invertida se toman como parte de un número posible de retroreferencias. Si el patrón continúa con un carácter dígito, entonces se deben usar algunos delimitadores para finalizar la retroreferencia. Si la opción PCRE_EXTENDED está establecida, éste puede ser un espacio en blanco. De otra manera se puede usar un comentario vacío.

Una retroreferencia que sucede dentro de los paréntesis a los cuales se refiere, falla cuando el sub-patrón se usa primero, así, por ejemplo, (a\1) nunca coincide. Sin embargo, tales referencias pueden ser útiles dentro de sub-patrones repetidos. Por ejemplo, el patrón (a|b\1)+ coincide con cualquier número de "a"es y tambíen con "aba", "ababba", etc. En cada iteración del subpatrón, la retroreferencia coincide con el cadena correspondiente a la iteración anterior. Para que esto funcione, el patrón debe ser tal que la primera iteración no necesite coincidir con la retroreferencia. Esto se puede lograr usando alternancia, como en el ejemplo anterior, o mediante un cuantificador con un mínimo de cero.

A partir de PHP 5.2.2, la secuencia de escape \g se puede usar para referenciar subpatrones de forma absoluta y relativa. Esta secuencia de escape debe estar seguida por un número sin signo o un número negativo, opcionalmente encerrado entre llaves. Las secuencias \1, \g1 y \g{1} son sinónimas unas de otras. El uso de este patrón con un número sin signo puede ayudar a eliminar la ambigüedad inherente al usar dígitos seguidos de una barra invertida. La secuencia ayuda a distinguir retroreferencias de caracteres octales y también hace más fácil tener una retroreferencia seguida por un número literal, p.ej. \g{2}1.

El uso de la secuencia \g con un número negativo significa una referencia relativa. Por ejemplo, (foo)(bar)\g{-1} coincidiría con la secuencia "foobarbar" y (foo)(bar)\g{-2} coincidiría con "foobarfoo". Esto puede ser útil en patrones largos como una alternativa de seguir la pista del número de subpatrones para referenciar un subpatrón previo específico.

Las retroreferencias a sub-patrones nominados se pueden lograr mediante (?P=nombre) o, desde PHP 5.2.2, también mediante \k<nombre> o \k'nombre'. Además, PHP 5.2.4 añadió soporte para \k{nombre} y \g{nombre}, y PHP 5.2.7 para \g<name> y \g'name'.

add a note

User Contributed Notes 2 notes

up
13
mnvx at yandex dot ru
7 years ago
Something similar opportunity is DEFINE.

Example:
(?(DEFINE)(?<myname>\bvery\b))(?&myname)\p{Pd}(?&myname).

Expression above will match "very-very" from next sentence:
Define is very-very handy sometimes.
^-------^

How it works. (?(DEFINE)(?<myname>\bvery\b)) - this block defines "myname" equal to "\bvery\b". So, this block "(?&myname)\p{Pd}(?&myname)" equvivalent to "\bvery\b\p{Pd}\bvery\b".
up
0
Steve
1 year ago
The escape sequence \g used as a backreference may not always behave as expected.
The following numbered backreferences refer to the text matching the specified capture group, as documented:
\1
\g1
\g{1}
\g-1
\g{-1}

However, the following variants refer to the subpattern code instead of the matched text:
\g<1>
\g'1'
\g<-1>
\g'-1'

With named backreferences, we may also use the \k escape sequence as well as the (?P=...) construct. The following combinations also refer to the text matching the named capture group, as documented:
\g{name}
\k{name}
\k<name>
\k'name'
(?P=name)

However, these refer to the subpattern code instead of the matched text:
g<name>
\g'name'

In the following example, the capture group searches for a single letter 'a' or 'b', and then the backreference looks for the same letter. Thus, the patterns are expected to match 'aa' and 'bb', but not 'ab' nor 'ba'.

<?php
/* Matches to the following patterns are replaced by 'xx' in the subject string 'aa ab ba bb'. */
$patterns = [
# numbered backreferences (absolute)
'/([ab])\1/', // 'xx ab ba xx'
'/([ab])\g1/', // 'xx ab ba xx'
'/([ab])\g{1}/', // 'xx ab ba xx'
'/([ab])\g<1>/', // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
"/([ab])\g'1'/", // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
'/([ab])\k{1}/', // 'aa ab ba bb' # No group with name "1", backreference to unset group always fails.
'/([ab])\k<1>/', // 'aa ab ba bb' # No group with name "1", backreference to unset group always fails.
"/([ab])\k'1'/", // 'aa ab ba bb' # No group with name "1", backreference to unset group always fails.
'/([ab])(?P=1)/', // NULL # Regex error: "subpattern name must start with a non-digit", (?P=) expects name not number.
# numbered backreferences (relative)
'/([ab])\-1/', // 'aa ab ba bb'
'/([ab])\g-1/', // 'xx ab ba xx'
'/([ab])\g{-1}/', // 'xx ab ba xx'
'/([ab])\g<-1>/', // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
"/([ab])\g'-1'/", // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
'/([ab])\k{-1}/', // 'aa ab ba bb' # No group with name "-1", backreference to unset group always fails.
'/([ab])\k<-1>/', // 'aa ab ba bb' # No group with name "-1", backreference to unset group always fails.
"/([ab])\k'-1'/", // 'aa ab ba bb' # No group with name "-1", backreference to unset group always fails.
'/([ab])(?P=-1)/', // NULL # Regex error: "subpattern name expected", (?P=) expects name not number.
# named backreferences
'/(?<name>[ab])\g{name}/', // 'xx ab ba xx'
'/(?<name>[ab])\g<name>/', // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
"/(?<name>[ab])\g'name'/", // 'xx xx xx xx' # unexpected behavior, backreference matches both 'a' and 'b'.
'/(?<name>[ab])\k{name}/', // 'xx ab ba xx'
'/(?<name>[ab])\k<name>/', // 'xx ab ba xx'
"/(?<name>[ab])\k'name'/", // 'xx ab ba xx'
'/(?<name>[ab])(?P=name)/', // 'xx ab ba xx'
];

foreach (
$patterns as $pat)
echo
" '$pat',\t// " . var_export(@preg_replace($pat, 'xx', 'aa ab ba bb'), 1) . PHP_EOL;
?>
To Top