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.*Zy A.*?Z.
Dada la siguiente entrada:
eeeAiiZuuuuAoooZeeee
Los patrones producen las siguientes coincidencias:
Primero centrémonos en lo que A.*Zhace. Cuando coincide con el primero A, el .*, siendo codicioso, primero intenta igualar tantos .como sea posible.
eeeAiiZuuuuAoooZeeee
\_______________/
A.* matched, Z can't match
Como Zno 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 Zpuede coincidir, por lo que el patrón general coincide:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
Por el contrario, la repetición reacia en los A.*?Zprimeros 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]*Ztambién encuentra las mismas dos coincidencias que el A.*?Zpatró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