W3docs

Cuantificadores codiciosos y perezosos

Aprende cómo funcionan los cuantificadores codiciosos y perezosos en las expresiones regulares de JavaScript: el modo codicioso consume el máximo y retrocede, mientras que el perezoso (*?, +?, ??, {n,m}?) toma el mínimo.

Un cuantificador como *, + o ? le indica a una expresión regular cuántas veces puede repetirse el patrón anterior. Pero cuando varios fragmentos de texto de diferente longitud satisfacen el patrón, el motor debe decidir cuál tomar. Esa decisión es la que controlan los cuantificadores codiciosos y perezosos.

Por defecto, todo cuantificador es codicioso: toma tantos caracteres como sea posible. Añadir un ? después del cuantificador lo convierte en perezoso: toma los menos posibles. Elegir el modo incorrecto es uno de los errores más comunes con las expresiones regulares — el síntoma clásico es un patrón que "coincide demasiado". Esta página explica el mecanismo detrás de ambos modos para que puedas elegir el correcto de manera deliberada.

Cómo funciona realmente la coincidencia codiciosa: consumir y luego retroceder

Un cuantificador codicioso no sabe mágicamente dónde detenerse. Trabaja en dos fases:

  1. Consumir el máximo. .* primero se traga el resto completo de la cadena.
  2. Retroceder. Si el patrón que sigue a .* ya no puede coincidir (porque todo ha sido consumido), el motor devuelve caracteres de uno en uno, reintentando después de cada uno, hasta que todo el patrón encaje.

Así que codicioso significa "tomar todo, y luego devolver a regañadientes el mínimo necesario para que el resto del patrón tenga éxito." Entender el paso de retroceso es la clave para predecir qué hacen los patrones codiciosos.

* codicioso en acción


javascript— editable

Aquí .* coincide con cualquier carácter cero o más veces. Como no hay nada requerido después de él, no se necesita retroceso y conserva todo hasta el final de la línea, produciendo "ABCD*E".

+ codicioso en acción


javascript— editable

C+ coincide con "C" una o más veces y codiciosamente toma las tres, por lo que la coincidencia es "ABCCC".

Cómo funciona la coincidencia perezosa: consumir el mínimo y luego expandirse

Un cuantificador perezoso invierte la estrategia:

  1. Consumir el mínimo. .*? comienza coincidiendo con nada.
  2. Expandirse. Solo si el resto del patrón no logra coincidir, el motor permite que el cuantificador perezoso tome un carácter más, y luego reintenta — repitiendo esto hasta que todo el patrón tenga éxito.

Así que perezoso significa "tomar lo menos posible, y crecer solo cuando sea obligado." Cualquier cuantificador se vuelve perezoso añadiendo ? al final.

*? perezoso en acción


javascript— editable

Este es el caso confuso. El resultado es simplemente "AB". ¿Por qué? Porque .*? puede coincidir con nada, y no hay nada después de él en el patrón que fuerce más consumo. En cuanto AB coincide, el patrón ya está completo, por lo que el cuantificador perezoso se detiene felizmente en cero caracteres. Un cuantificador perezoso solo se expande cuando algo que le sigue — un delimitador, un literal o un ancla — lo exige.

+? perezoso en acción


javascript— editable

C+? debe coincidir con al menos una "C" (eso es lo que requiere +), y nada después de él pide más, así que se detiene en la primera: "ABC".

El ejemplo canónico: <.*> vs <.*?>

La diferencia entre codicioso y perezoso es más fácil de ver cuando hay algo después del cuantificador. Hacer coincidir etiquetas HTML es el caso de manual. Ejecuta ambos patrones sobre la misma cadena:


javascript— editable
  • Codicioso /<.*>/ coincide con "<p>Hello</p>" — toda la cadena. .* consume todo, luego retrocede justo lo suficiente para dejar un > para el > final en el patrón, aterrizando en el último >.
  • Perezoso /<.*?>/ coincide solo con "<p>" — una sola etiqueta. .*? se expande carácter por carácter y se detiene en el instante en que alcanza el primer >.

Cuando tu objetivo es "coincidir con una etiqueta", "coincidir con una cadena entre comillas" o "coincidir hasta el siguiente delimitador", el modo perezoso es casi siempre lo que necesitas.

La familia completa de cuantificadores perezosos

Cada cuantificador codicioso tiene un gemelo perezoso que se forma añadiendo ?:

CodiciosoPerezosoSignificado de la forma perezosa
**?Cero o más, los menos posibles
++?Uno o más, los menos posibles
???Cero o uno, prefiere cero
{2,5}{2,5}?Entre 2 y 5, prefiere 2
{2,}{2,}?Al menos 2, prefiere 2

Nótese que ?? no es un error tipográfico: el primer ? es el cuantificador (cero o uno) y el segundo lo hace perezoso, por lo que prefiere no coincidir con nada cuando tiene opción.


javascript— editable

¿Cuándo deberías usar cuantificadores perezosos?

Una regla práctica:

Usa un cuantificador perezoso cuando quieras coincidir hasta la primera ocurrencia de un delimitador, y codicioso cuando quieras todo hasta el último.

Situaciones comunes en las que el modo perezoso es la elección correcta:

  • Extraer una sola etiqueta HTML/XML: /<.*?>/.
  • Capturar el contenido de un par de comillas o corchetes: /".*?"/, /\(.*?\)/.
  • Obtener texto hasta el siguiente separador sin pasarse al registro siguiente.

Dos advertencias importantes:

  • Un delimitador suele ser más claro que la pereza. En lugar de /".*?"/ puedes escribir /"[^"]*"/ con una clase de caracteres negada. Esto evita el retroceso por completo y suele ser más rápido y predecible.
  • El modo perezoso necesita algo en qué detenerse. Como mostró el ejemplo AB.*?, un cuantificador perezoso al final de un patrón (sin nada que lo impulse hacia adelante) colapsa a su mínimo y coincide con casi nada. Combínalo con un literal siguiente, un ancla o un grupo de captura.

Resumen

  • Los cuantificadores son codiciosos por defecto — toman el máximo, luego retroceden para que el resto del patrón encaje.
  • Añade ? para hacer un cuantificador perezoso — toma el mínimo, luego se expande solo cuando es obligado.
  • Un cuantificador perezoso sin nada después coincide con lo menos que legalmente puede (a menudo nada), así que dale siempre un delimitador o ancla en qué detenerse.
  • La familia perezosa completa es *?, +?, ?? y {n,m}?.
  • Elige el modo perezoso cuando quieras coincidir "hasta el primer" delimitador; de lo contrario, una clase de caracteres negada suele ser la opción más limpia y rápida.

Práctica

Práctica
Dado el string '<p>Hi</p>', ¿con qué coincide el patrón perezoso /<.*?>/
Dado el string '<p>Hi</p>', ¿con qué coincide el patrón perezoso /<.*?>/
Was this page helpful?