Guías1 caza jugable incluida

Cuantificadores codiciosos y perezosos: por qué .* come de más

Los cuantificadores de una regex se quedan con todo el texto que pueden. Así funcionan de verdad las coincidencias codiciosas y perezosas, por qué <.+> se traga una línea entera de HTML y cuándo una clase negada gana a las dos.

Logo de Regex Hunter

· 6 min de lectura

/<.+?>/

atrapa

  • <b>
  • </i>
  • <br>

deja libre

  • b
  • i>
  • <>

Escribes <.+> para atrapar una etiqueta HTML, lo pruebas con <b>bold</b> y coincide con toda la cadena: las dos etiquetas y el texto entre ellas. No hay nada roto. El cuantificador hizo exactamente aquello para lo que está diseñado: quedarse con todo lo que pueda.

Este artículo explica qué hacen de verdad los cuantificadores codiciosos (greedy) y perezosos (lazy), por qué la diferencia solo se nota en qué coincide y por qué la mejor solución a menudo no es ninguno de los dos.

01Codicioso: tómalo todo y luego devuelve

Los cuantificadores *, +, ? y {n,m} son codiciosos por defecto. Coinciden con tantos caracteres como pueden y solo devuelven caracteres si el resto del patrón falla.

Coincidencias1/1 como se esperaba
/<.+>/
  • <b>bold</b> and <i>it</i>
Pruébalo en la Zona de pruebas
Una sola coincidencia, desde el primer < hasta el último >. El .+ llegó hasta el final de la línea y luego retrocedió lo justo para encontrar un >.

Esto es lo que hace el motor con <.+>:

  1. < coincide con el primer carácter.
  2. .+ se traga todo hasta el final de la línea.
  3. A > ya no le queda nada con lo que coincidir, así que el motor retrocede (backtracking): .+ devuelve un carácter cada vez hasta que > encaja.
  4. El primer > que encuentra al retroceder es el último de la línea. Coincidencia encontrada.

02Perezoso: toma lo menos posible

Añade un ? después de cualquier cuantificador y se vuelve perezoso: coincide con el menor número de caracteres posible y solo toma más cuando el resto del patrón falla.

Coincidencias1/1 como se esperaba
/<.+?>/
  • <b>bold</b> and <i>it</i>
Pruébalo en la Zona de pruebas
Cuatro coincidencias separadas, una por etiqueta. El perezoso .+? se para en el primer > que puede.

Las versiones perezosas de cada cuantificador:

Codicioso Perezoso Significado
* *? cero o más
+ +? uno o más
? ?? opcional
{2,5} {2,5}? entre 2 y 5

Lo mismo pasa con las cadenas entre comillas. El codicioso va de la primera comilla a la última. El perezoso se para en la siguiente comilla:

Coincidencias1/1 como se esperaba
/".*?"/
  • say "hi" and "bye"
Pruébalo en la Zona de pruebas
Dos coincidencias, "hi" y "bye". El codicioso ".*" abarcaría "hi" and "bye" como una sola cadena, comillas del medio incluidas.

03A menudo mejor que los dos: una clase negada

Los cuantificadores perezosos siguen intentando que . coincida con cada carácter, incluido aquel en el que quieres parar. Una clase de caracteres negada expresa la regla de parada directamente: “cualquier cosa menos >”.

Coincidencias1/1 como se esperaba
/<[^>]+>/
  • <b>bold</b> and <i>it</i>
Pruébalo en la Zona de pruebas
Las mismas cuatro etiquetas que con la versión perezosa, pero la regla está en la propia clase. [^>] nunca puede pasar de un >.

<[^>]+> y "[^"]*" suelen ser la mejor opción:

  • Más claras. El patrón dice qué es una etiqueta, no cómo debe buscarla el motor.
  • Más rápidas. No hay backtracking: [^>]+ se para en el primer > por definición.
  • Funcionan entre líneas. . no coincide con un salto de línea por defecto, así que <.+?> se pierde una etiqueta partida en dos líneas. [^>] también coincide con los saltos de línea.

04La sorpresa: perezoso no es “la coincidencia más corta”

Perezoso significa lo más corta posible desde donde empieza la coincidencia. No mueve el inicio. El motor siempre devuelve la coincidencia que encuentre más a la izquierda:

Coincidencias1/1 como se esperaba
Quizá esperas “ab”, el trozo más corto. Pero la coincidencia empieza en la primera a, y desde ahí el perezoso .*? tiene que estirarse hasta llegar a la b.

Si quieres el a…b más corto sin ninguna a dentro, dilo otra vez con una clase: a[^a]*b.

05Por qué en el golf de regex da igual

Un dato útil para golfistas: codicioso o perezoso nunca cambia si una cadena coincide. a.*b y a.*?b coinciden exactamente con el mismo conjunto de palabras. Solo se diferencian en qué parte del texto devuelven. Como una caza solo pregunta “¿coincide esta palabra?”, un ? después de un cuantificador te cuesta un carácter y no te da nada.

Lo que sí ayuda en los tableros es la clase negada, porque cambia lo que puede coincidir. En este tablero, todos los monstruos tienen exactamente una a:

Caza jugablepar 13

Atrapa las palabras con exactamente una a.

Objetivos · 0/5 atrapados

  • catobjetivo
  • breadobjetivo
  • snakeobjetivo
  • plantobjetivo
  • magicobjetivo

Inocentes · 0 errores

  • bananainocente
  • datainocente
  • saladinocente
  • pluminocente
  • treeinocente

Escribe una regex: el tablero se actualiza mientras escribes.

Pruébalo en la Zona de pruebas
¿Te gustó? Cada día llega una nueva.Jugar la caza de hoy

06Referencia rápida

  • Codicioso (.*, .+): coincide con todo lo posible y luego retrocede. Es el comportamiento por defecto.
  • Perezoso (.*?, .+?): coincide con lo mínimo posible y luego se alarga. Añade ?.
  • Clase negada ([^>]*): coincide con cualquier cosa menos el carácter de parada. Suele ser la mejor herramienta cuando sabes dónde parar.
  • Perezoso y codicioso coinciden con las mismas cadenas. Se diferencian en lo que capturan, extraen o reemplazan.

07Sigue practicando