Los cuantificadores greedy, reluctant y possessive en expresiones regulares

Publicado por pico.dev el .
blog-stack java planeta-codigo programacion
Comentarios

En el mundo de las expresiones regulares hay tres tipos de cuantificadores que varían el comportamiento según el número caracteres que toman para encontrar ocurrencias. Son greedy o avaricioso, reluctant o reacio y possesive o posesivo. Cada cuantificador tiene una expresión en una expresión regular. La opción más habitual es el cuantificador greedy, añadiendo una ? se convierte en reluctant y añadiendo un + se convierte en possesive.

Greedy  Reluctant  Possessive  Signigicado
X?      X??        X?+         X, uno o ninguno
X*      X*?        X*+         X, cero o mas
X+      X+?        X++         X, uno o más
X{n}    X{n}?      X{n}+       X, exactamente n veces
X{n,}   X{n,}?     X{n,}+      X, al menos n veces
X{n,m}  X{n,m}?    X{n,m}+     X, al menos n veces pero no mas de m

Aparentemente cada uno de los cuantificadores realiza lo mismo, sin embargo, hay diferencias en su comportamiento al hacer emparejamientos entre los elementos de la expresión regular y la cadena en la que se está aplicando.

  • Greedy o avaricioso: este cuantificador intenta obtener el emparejamiento más largo que pueda, tantos carecteres como pueda, si el emparejamiento no es válido elimina un caracter de la cadena que se está comprobando y lo intenta de nuevo.
  • Reluctant, reacio o vago: funciona al contrario que el cuantificador greedy, intentando inicialmente ningún caracter, tan pocos caracteres como pueda, si el emparejamiento no es válido añade un caracter de la cadena que se está comprobando y lo intenta de nuevo.
  • Possesive o posesivo: funciona igual que greedy salvo que si el emparejamiento no es válido no elimina un caracter de la cadena que se está comprobando y finaliza la comprobación.

En el primer ejemplo del cuantificador greedy se usa .* para encontrar cualquier cosa, cero o más veces, seguido de las letras f o o. Dado que el cuantificador de la expresión la expresión .* es avaricioso primero consume toda la cadena. En este punto, no hay coincidencia dado que las tres últimas letras (f o o) han sido consumidas. De modo quese busca con una letra menos sucesivamente hasta que la la ocurrencia más a la derecha de foo ha sido regurgitada, en este punto hay coincidencia y la búsqueda finaliza.

En el segundo ejemplo, sin embargo, el cuantificador es reacio o vago de modo que empieza consumiendo nada. Dado que foo no aparece en el inicio de la cadena es forzado a tomar la primera letra x con la que se encuentra la primera coincidencia entre 0 y 4. Se siguen encontrando coincidencias hata que la cadena de entrada ha sido consumida. Encuenta otra coincidencia en 4 y 13.

En el tercer caso se se hayan coincidencias ya que el cuantificador es posesivo. En este caso, la cadena completa es consuimida por .*+ dejando nada que satisfaga el patrón foo al final de la expresión. Dado que no vuelve hacia atrás tiene mejor rendimiento que el cuantoficador greedy en los casos que se quiera encontrar una coincidiencia completa en algo.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.