Regex lookahead, lookbehind y grupos atómicos

314

Encontré estas cosas en mi cuerpo de expresiones regulares, pero no tengo idea de para qué puedo usarlas. ¿Alguien tiene ejemplos para que yo pueda tratar de entender cómo funcionan?

(?!) - negative lookahead
(?=) - positive lookahead
(?<=) - positive lookbehind
(?<!) - negative lookbehind

(?>) - atomic group
Spidfire
fuente
18
¿Por qué el sitio web regex no tiene una tabla simple como esta? En cambio, tienen bloques de texto que solo explican. regular-expressions.info/lookaround.html
Whitecat
3
@Whitecat Prueba: regex101.com regexr.com
Andrew

Respuestas:

852

Ejemplos

Dada la cadena foobarbarfoo:

bar(?=bar)     finds the 1st bar ("bar" which has "bar" after it)
bar(?!bar)     finds the 2nd bar ("bar" which does not have "bar" after it)
(?<=foo)bar    finds the 1st bar ("bar" which has "foo" before it)
(?<!foo)bar    finds the 2nd bar ("bar" which does not have "foo" before it)

También puedes combinarlos:

(?<=foo)bar(?=bar)    finds the 1st bar ("bar" with "foo" before it and "bar" after it)

Definiciones

Mira hacia adelante positivo (?=)

Encuentre la expresión A donde sigue la expresión B:

A(?=B)

Mira hacia adelante negativo (?!)

Encuentre la expresión A donde la expresión B no sigue:

A(?!B)

Mira hacia atrás positivo (?<=)

Encuentre la expresión A donde la expresión B precede:

(?<=B)A

Mira hacia atrás negativo (?<!)

Encuentra la expresión A donde la expresión B no precede:

(?<!B)A

Grupos atómicos (?>)

Un grupo atómico sale de un grupo y arroja patrones alternativos después del primer patrón coincidente dentro del grupo (el retroceso está desactivado).

  • (?>foo|foot)saplicado a footscoincidirá con su primera alternativa foo, luego fallará como sno sigue inmediatamente y se detendrá cuando el retroceso esté deshabilitado

Un grupo no atómico permitirá retroceder; Si la coincidencia posterior falla, retrocederá y utilizará patrones alternativos hasta que se encuentre una coincidencia para toda la expresión o se agoten todas las posibilidades.

  • (foo|foot)saplicado a la footsvoluntad:

    1. iguala su primera alternativa foo, luego falla como sno sigue inmediatamente footsy retrocede a su segunda alternativa;
    2. iguale su segunda alternativa foot, luego triunfe como ssigue inmediatamente footsy pare.

Algunos recursos

Probadores en línea

skyfoot
fuente
1
¿Qué quieres decir con la parte "encuentra la segunda barra"? Solo hay una barra en la expresión / cadena. Gracias
ziggy
2
@ziggy la cadena que se prueba es "foobarbarfoo". Como puede ver, hay dos foo y dos barras en la cadena.
skyfoot
44
¿Alguien puede explicar cuándo se necesita un grupo atómico? Si solo necesito coincidir con la primera alternativa, ¿por qué querría dar varias alternativas?
arviman
2
Mejor explicación sobre el grupo atómico en esta respuesta . ¿Alguien puede editar aquí para completar esta respuesta didáctica?
Peter Krauss el
55
Solo una nota de que esta respuesta fue esencial cuando terminé en un proyecto que requería chuletas de expresión regular. Esta es una explicación excelente y concisa de las miradas.
Tom Coughlin
215

Lookarounds son aserciones de ancho cero. Verifican si hay una expresión regular (hacia la derecha o hacia la izquierda de la posición actual, basada en adelante o atrás), tiene éxito o falla cuando se encuentra una coincidencia (en función de si es positiva o negativa) y descarta la parte coincidente. No consumen ningún carácter: la coincidencia para la expresión regular que los sigue (si corresponde) comenzará en la misma posición del cursor.

Lea regular-expression.info para más detalles.

  • Positiva anticipada:

Sintaxis:

(?=REGEX_1)REGEX_2

Coincidir solo si REGEX_1 coincide; después de hacer coincidir REGEX_1, la coincidencia se descarta y la búsqueda de REGEX_2 comienza en la misma posición.

ejemplo:

(?=[a-z0-9]{4}$)[a-z]{1,2}[0-9]{2,3}

REGEX_1 es el [a-z0-9]{4}$que coincide con cuatro caracteres alfanuméricos seguidos por el final de la línea.
REGEX_2 es ​​el [a-z]{1,2}[0-9]{2,3}que coincide con una o dos letras seguidas de dos o tres dígitos.

REGEX_1 se asegura de que la longitud de la cadena sea de hecho 4, pero no consume ningún carácter para que la búsqueda de REGEX_2 comience en la misma ubicación. Ahora REGEX_2 se asegura de que la cadena coincida con algunas otras reglas. Sin mirar hacia adelante, coincidiría con cadenas de longitud tres o cinco.

  • Lookahead negativo

Sintaxis:

(?!REGEX_1)REGEX_2

Coincidir solo si REGEX_1 no coincide; después de verificar REGEX_1, la búsqueda de REGEX_2 comienza en la misma posición.

ejemplo:

(?!.*\bFWORD\b)\w{10,30}$

La parte de anticipación verifica FWORDla cadena y falla si la encuentra. Si no encuentra FWORD, la búsqueda anticipada tiene éxito y la siguiente parte verifica que la longitud de la cadena esté entre 10 y 30 y que solo contenga caracteres de palabrasa-zA-Z0-9_

El mirar hacia atrás es similar al mirar hacia adelante: solo mira detrás de la posición actual del cursor. Algunos sabores de expresiones regulares como javascript no admiten aserciones de retrospectiva. Y la mayoría de los sabores que lo admiten (PHP, Python, etc.) requieren que la porción retrospectiva tenga una longitud fija.

  • Los grupos atómicos básicamente descartan / olvidan los tokens posteriores en el grupo una vez que un token coincide. Consulte esta página para ver ejemplos de grupos atómicos.
Amarghosh
fuente
siguiendo su explicación, no parece funcionar en javascript, /(?=source)hello/.exec("source...hummhellosource ") = nulo. ¿Es correcta su explicación?
Helin Wang
@HelinWang Esa explicación es correcta. ¡Su expresión regular espera una cadena que sea fuente y hola al mismo tiempo!
Amarghosh
@jddxf ¿Quieres elaborar?
Amarghosh
@Amarghosh Estoy de acuerdo con "Comprueban una expresión regular (hacia la derecha o hacia la izquierda de la posición actual, basada en adelante o atrás), tiene éxito o falla cuando se encuentra una coincidencia (en función de si es positiva o negativa) y descarta la coincidencia parte.". Por lo tanto, la búsqueda anticipada debe verificar una expresión regular hacia la derecha de la posición actual y la sintaxis de la búsqueda positiva hacia adelante debe ser x (? = Y)
jddxf
@Amarghosh (?=REGEX_1)REGEX_2solo coincidiría si REGEX_2viene después REGEX_1 ?
aandis
0

Grokking busca rápidamente.
¿Cómo distinguir lookahead y lookbehind? Toma 2 minutos de recorrido conmigo:

(?=) - positive lookahead
(?<=) - positive lookbehind

Suponer

    A  B  C #in a line

Ahora le preguntamos a B: ¿Dónde estás?
B tiene dos soluciones para declararlo ubicación:

Uno, B tiene A adelante y tiene C bebind
Dos, B está adelante (hacia adelante) de C y detrás (mirar hacia atrás) A.

Como podemos ver, el atrás y el adelante son opuestos en las dos soluciones.
Regex es la solución dos.

Cálculo
fuente