Saltar al contenido

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

Solución:

Sobre codiciosos vs no codiciosos

La repetición en expresiones regulares por defecto es avaro: 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 encontrar una coincidencia de todo el patrón. Como resultado, cuando finalmente ocurre una coincidencia, una repetición codiciosa coincidiría como muchos repeticiones como sea posible.

los ? como un cuantificador de repetición cambia este comportamiento en no codicioso, también llamado reacio (en, por ejemplo, Java) (ya veces “perezoso”). Por el contrario, esta repetición primero intentará coincidir como pocos repeticiones como sea posible, y cuando esto no funciona y tienen que retroceder, comienzan a emparejar un reptil más por vez. Como resultado, cuando finalmente ocurre una coincidencia, una repetición reacia coincidiría como pocos repeticiones como sea posible.

Referencias

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

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:

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

Centrémonos primero en lo que A.*Z lo hace. Cuando coincidió con el primero A, los .*, siendo codicioso, primero intenta igualar tantos . como sea posible.

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

Desde el Z no coincide, el motor retrocede y .* luego debe coincidir con uno menos .:

eeeAiiZuuuuAoooZeeee
   ______________/
    A.* matched, Z still can't match

Esto sucede unas cuantas 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 reacia repetición en A.*?Z primeros partidos como 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 coincidían 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, un reacio .*? se usa en lugar del codicioso .* para evitar el exceso de coincidencia. Sin embargo, para este patrón en particular, existe una alternativa mejor, utilizando la clase de caracteres negada.

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 un clase de carácter negado: coincide con cualquier cosa menos Z.

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

Referencias

  • regular-expressions.info/Repetition: una alternativa a la pereza, las clases de caracteres negadas y los cuantificadores posesivos

Ejemplo 2: de la A a la ZZ

Este ejemplo debe ser ilustrativo: muestra cómo los patrones de clase de caracteres codiciosos, reacios y negados coinciden de manera diferente con la misma entrada.

eeAiiZooAuuZZeeeZZfff

Estas son las coincidencias para la entrada anterior:

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

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 sobre stackoverflow que cubren algunos temas que pueden ser de interés.

Una repetición codiciosa puede superado otro

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

Es la diferencia entre cuantificadores codiciosos y no codiciosos.

Considere la entrada 101000000000100.

Utilizando 1.*1, * es codicioso: coincidirá hasta el final, y luego retrocederá hasta que pueda coincidir 1, dejándote con 1010000000001.
.*? no es codicioso. * no coincidirá con nada, pero luego intentará hacer coincidir caracteres adicionales hasta que coincida 1, eventualmente coincidiendo 101.

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

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

Ver Hoja de referencia del cuantificador.

Digamos que tienes:

<a></a>

<(.*)> coincidiría a></a mientras que <(.*?)> coincidiría a. Este último se detiene después del primer partido de >. Comprueba si hay una o 0 coincidencias de .* seguido de la siguiente expresión.

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

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *