22

Estoy aprendiendo RegEx, y me llamó mucho la atención un ejemplo de:
Regex Golf (ver nivel 6, "Abba")

El problema planteado es filtrar todas las palabras que no contengan letras que sigan el patron XYYX.

Por ejemplo, dejando fuera:

  • abba
  • anallagmatic
  • bassarisk
  • chorioallantois
  • coccomyces


Una de las respuestas sugeridas fue

^(?!.*(.)(.)\2\1)

Regular expression visualization

Debuggex Demo


He aquí mi interpretación de la expresión:

  1. Inicio de la linea ^
  2. Si no es seguido de 0 o + caracteres .*
  3. Agrupa el siguiente caracter en 1 (.)
  4. Agrupa el siguiente caracter en 2 (.)
  5. Grupo 2 \2
  6. Grupo 1 \1

El problema es que, a pesar de que ya empiezo a escribir mis primeras expresiones regulares y ya he hecho algunos ejercicios, este problema en particular me deja muchas dudas.

¿Alguien puede dar una interpretación más intuitiva?

Mariano
  • 23,777
  • 20
  • 70
  • 102
The One
  • 1,022
  • 2
  • 11
  • 19

1 Answers1

23

Aquí hay otra explicación:

  • ^, inicio de cadena
  • (?!, mirar hacia adelante para ver si no hay lo siguiente
  •    .*, cualquier carácter (excepto \n), la mayor cantidad posible
  •    (.), cualquier carácter (excepto \n), 1er grupo
  •    (.), cualquier carácter (excepto \n), 2do grupo
  •    \2, lo mismo que el 2do grupo
  •    \1, lo mismo que el 1er grupo
  • ), fin de mirar hacia adelante

Lo que hace esta expresión regular es buscar en la cadena un texto que no sea seguido (desde el principio de la misma) por el patrón .*(.)(.)\2\1.

Por ejemplo, para la cadena anallagmatic, el patrón .*(.)(.)\2\1 se cumple en anallagmatic. Sin embargo, como no desea encontrarse tal patrón en la cadena, entonces la expresión regular completa, ^(?!.*(.)(.)\2\1), no se cumple.

Dependiendo de la implementación del motor de expresiones regulares 1, este buscará el patrón, basándose en la expresión regular (regex-directed) o en el texto (text-directed), en la cadena e informará si fue encontrado o no.

Por ejemplo, el Regex Debugger del sitio https://regex101.com/ muestra los pasos realizados por el motor hasta «fallar» (no encontrar coincidencias) con el texto anallagmatic:


Notas

  1. Véase First Look at How a Regex Engine Works Internally (en inglés).
Paul Vargas
  • 181
  • 1
  • 20
  • 39
  • Ya entiendo `(.)(.)\1\2`, esto es el patron `ABBA` donde `A=1 B=2` y por ende `\2\1= BA` todo esto es igual a `ABBA`, pero no entiendo la logica en `.*` – The One Apr 28 '16 at 13:55
  • @Tuco Primero, la expresión **debe** estar anclada a `^`, de lo contrario podría coincidir desde `abbaxxxx` por ejemplo (que es lo opuesto a lo deseado). Ahora bien, como está anclado al inicio del texto, `.*` permite que se consuman los caracteres necesarios para que la parte importante (`(.)(.)\2\1`) pueda encontrar la coincidencia. Y, cuando esa coincidencia ocurre, como está dentro de una aserción negativa, el intento global falla. – Mariano Mar 23 '17 at 17:45