En codicioso vs no codicioso
La repetición en regex por defecto es codiciosa : intentan igualar tantas repeticiones como sea posible, y cuando esto no funciona y tienen que retroceder, intentan igualar una repetición menos a la vez, hasta que coincida con todo el patrón. encontró. Como resultado, cuando finalmente ocurre una coincidencia, una repetición codiciosa coincidiría con tantas repeticiones como sea posible.
El ?
cuantificador como repetición cambia este comportamiento a no codicioso , también llamado reacio ( en, por ejemplo, Java ) (y a veces "perezoso"). En contraste, esta repetición primero intentará igualar la menor cantidad posible de repeticiones, y cuando esto no funciona y tienen que retroceder, comienzan a emparejar un reptil más a la vez. Como resultado, cuando finalmente ocurre una coincidencia, una repetición reacia coincidiría con la menor cantidad posible de repeticiones.
Referencias
Ejemplo 1: de la A a la Z
Comparemos estos dos patrones: A.*Z
y A.*?Z
.
Dada la siguiente entrada:
eeeAiiZuuuuAoooZeeee
Los patrones producen las siguientes coincidencias:
Primero centrémonos en lo que A.*Z
hace. Cuando coincide con el primero A
, el .*
, siendo codicioso, primero intenta igualar tantos .
como sea posible.
eeeAiiZuuuuAoooZeeee
\_______________/
A.* matched, Z can't match
Como Z
no coincide, el motor retrocede, y .*
luego debe coincidir con uno menos .
:
eeeAiiZuuuuAoooZeeee
\______________/
A.* matched, Z still can't match
Esto sucede algunas veces más, hasta que finalmente llegamos a esto:
eeeAiiZuuuuAoooZeeee
\__________/
A.* matched, Z can now match
Ahora Z
puede coincidir, por lo que el patrón general coincide:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
Por el contrario, la repetición reacia en los A.*?Z
primeros partidos lo menos .
posible, y luego tomar más .
según sea necesario. Esto explica por qué encuentra dos coincidencias en la entrada.
Aquí hay una representación visual de lo que coincidieron los dos patrones:
eeeAiiZuuuuAoooZeeee
\__/r \___/r r = reluctant
\____g____/ g = greedy
Ejemplo: una alternativa
En muchas aplicaciones, las dos coincidencias en la entrada anterior es lo que se desea, por lo tanto, .*?
se utiliza un reacio en lugar del codicioso .*
para evitar la coincidencia excesiva. Sin embargo, para este patrón en particular, existe una alternativa mejor, utilizando la clase de caracteres negados.
El patrón A[^Z]*Z
también encuentra las mismas dos coincidencias que el A.*?Z
patrón para la entrada anterior ( como se ve en ideone.com ). [^Z]
es lo que se llama una clase de caracteres negados : coincide con cualquier cosa menos Z
.
La principal diferencia entre los dos patrones está en el rendimiento: al ser más estricta, la clase de caracteres negados solo puede coincidir en un sentido para una entrada determinada. No importa si usa un modificador codicioso o reacio para este patrón. De hecho, en algunos sabores, puedes hacerlo aún mejor y usar lo que se llama cuantificador posesivo, que no retrocede en absoluto.
Referencias
Ejemplo 2: de A a ZZ
Este ejemplo debería ser ilustrativo: muestra cómo los patrones de clase de caracteres codiciosos, renuentes y negados coinciden de manera diferente dada la misma entrada.
eeAiiZooAuuZZeeeZZfff
Estas son las coincidencias para la entrada anterior:
Aquí hay una representación visual de lo que coincidieron:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
Temas relacionados
Estos son enlaces a preguntas y respuestas en stackoverflow que cubren algunos temas que pueden ser de interés.
Una repetición codiciosa puede superar a otra