Cuál es la diferencia entre .*? y. * expresiones regulares?

Estoy tratando de dividir una cadena en dos partes usando expresiones regulares. La cadena está formateada de la siguiente manera:

text to extract 

He estado usando (.*?)< Y Que funcionan bien, pero después de leer un poco sobre Regex, acabo de empezar a preguntarme por qué necesito el ? en las expresiones. Solo lo hice así después de encontrarlos en este sitio, así que no estoy exactamente seguro de cuál es la diferencia.

Es la diferencia entre cuantificadores codiciosos y no codiciosos.

Considere la entrada 101000000000100 .

Usar 1.*1 , * es codicioso: coincidirá hasta el final y luego retrocede hasta que pueda coincidir con 1 , dejándote con 1010000000001 .
.*? no es codicioso * no coincidirá con nada, pero luego intentará unir los caracteres adicionales hasta que coincida con 1 , eventualmente haciendo coincidir 101 .

Todos los cuantificadores tienen un modo no codicioso:. .*? , .+? , .{2,6}? e incluso .?? .

En su caso, un patrón similar podría ser < ([^>]*)> – haciendo coincidir cualquier cosa que no sea un signo mayor que (estrictamente hablando, coincide con cero o más caracteres distintos de > entre-y < y > ).

Vea la Hoja de trucos de Quantifier .

En codiciosos vs no codiciosos

La repetición en expresiones regulares por defecto es codiciosa : intentan coincidir tantas repeticiones como sea posible, y cuando esto no funciona y tienen que dar marcha atrás, intentan emparejar un representante menos a la vez, hasta que coincida un patrón completo. encontró. Como resultado, cuando finalmente ocurre un partido, una repetición codiciosa coincidirá con tantas repeticiones como sea posible.

El ? como un cuantificador de repetición cambia este comportamiento a no codicioso , también llamado reacio ( en, por ejemplo, Java ) (y, a veces “perezoso”). Por el contrario, esta repetición primero intentará hacer coincidir el menor número de repeticiones posible, y cuando esto no funciona y tienen que dar marcha atrás, comienzan a emparejar un reptil más por vez. Como resultado, cuando finalmente se produce una coincidencia, una repetición reacia coincidiría con la menor cantidad posible de representantes.

Referencias

  • regular-expressions.info/Repetition – Pereza en lugar de Greediness

Ejemplo 1: De la A a la Z

Comparemos estos dos patrones: A.*Z y A.*Z A.*?Z

Dada la siguiente entrada:

 eeeAiiZuuuuAoooZeeee 

Los patrones producen las siguientes coincidencias:

  • A.*Z produce 1 coincidencia: AiiZuuuuAoooZ ( ver en rubular.com )
  • A.*?Z rinde 2 coincidencias: AiiZ y AoooZ ( ver en rubular.com )

Primero, concéntrese en lo que hace A.*Z Cuando coincidía con la primera A , el .* , Siendo codicioso, primero intenta igualar a tantos . como sea posible.

 eeeAiiZuuuuAoooZeeee \_______________/ A.* matched, Z can't match 

Como la Z no coincide, el motor retrocede, y .* 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 A.*?Z primero coincide con pocos . como sea 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 coinciden los dos patrones:

 eeeAiiZuuuuAoooZeeee \__/r \___/rr = reluctant \____g____/ g = greedy 

Ejemplo: una alternativa

En muchas aplicaciones, las dos coincidencias en la entrada anterior son las deseadas, por lo tanto, son reacias .*? se usa en lugar de codicioso .* para evitar el exceso de coincidencia. Para este patrón particular, sin embargo, hay una mejor alternativa, utilizando una clase de caracteres negada.

El patrón A[^Z]*Z también encuentra las mismas dos coincidencias que el patrón A.*?Z para la entrada anterior ( como se ve en ideone.com ). [^Z] es lo que se llama una clase de carácter negada : coincide con todo menos con Z

La principal diferencia entre los dos patrones está en el rendimiento: al ser más estricto, la clase de carácter negada solo puede coincidir de una manera con una entrada determinada. No importa si usa un modificador codicioso o renuente para este patrón. De hecho, en algunos sabores, puedes hacerlo aún mejor y usar lo que se llama cuantificador posesivo, que no se retrasa en absoluto.

Referencias

  • regular-expressions.info/Repetition – Una alternativa a la pereza , clases de caracteres negados y cuantificadores posesivos

Ejemplo 2: De A a ZZ

Este ejemplo debe ser ilustrativo: muestra cómo los patrones de clase de carácter codicioso, renuente y negado coinciden de manera diferente dada la misma entrada.

 eeAiiZooAuuZZeeeZZfff 

Estas son las coincidencias para la entrada anterior:

  • A[^Z]*ZZ produce 1 coincidencia: AuuZZ ( como se ve en ideone.com )
  • A.*?ZZ produce 1 coincidencia: AiiZooAuuZZ ( como se ve en ideone.com )
  • A.*ZZ produce 1 coincidencia: AiiZooAuuZZeeeZZ ( como se ve en ideone.com )

Aquí hay una representación visual de lo que coinciden:

  ___n / \ n = negated character class eeAiiZooAuuZZeeeZZfff r = reluctant \_________/r / g = greedy \____________/g 

Temas relacionados

Estos son enlaces a preguntas y respuestas sobre stackoverflow que cubren algunos temas que pueden ser de su interés.

Una repetición codiciosa puede pasar a otro

  • Regex no es lo suficientemente codicioso
  • Expresión regular: quién es más codicioso

Digamos que tienes:

  

< (.*)> coincidiría con a> donde como < (.*?)> coincidiría con a . Este último se detiene después del primer partido de > . Comprueba una o 0 coincidencias de .* Seguido de la siguiente expresión.

La primera expresión < (.*)> No se detiene al hacer coincidir los primeros > . Continuará hasta el último partido de > .