Lookahead y Lookbehind en Regex: Ejemplos Claros
Dev Tools

Lookahead y Lookbehind en Regex: Ejemplos Claros

El Lookaround Es Solo una Aserción Sobre la Posición

La mayor parte de la confusión con lookahead y lookbehind nace de un malentendido — la gente espera que coincidan con texto. No lo hacen. El lookaround es una aserción de ancho cero: comprueba si una condición es cierta en la posición actual y devuelve el control sin consumir ni un solo carácter. El cursor se queda exactamente donde estaba. Cuando eso encaja, todos los patrones de abajo dejan de ser misteriosos. Puedes verificar cada uno en vivo pegándolos en nuestro Probador de Regex y observando qué se resalta frente a qué solo se comprueba.

La especificación ECMAScript define estas construcciones en la producción Assertion de la gramática de expresiones regulares (ECMA-262, sección 22.2.1, "Patterns"). El lookahead existe en JavaScript desde el principio; el lookbehind y los grupos con nombre se estandarizaron en ES2018. Esa historia importa porque el lookbehind es la única función que aún no puedes dar por hecha en todo runtime antiguo, un punto al que volvemos al final.

Las Cuatro Formas de un Vistazo

Hay exactamente cuatro operadores de lookaround, y se emparejan limpiamente en dos ejes — dirección y polaridad.

  • Lookahead positivo (?=…) — "lo que sigue aquí coincide con X".
  • Lookahead negativo (?!…) — "lo que sigue aquí no coincide con X".
  • Lookbehind positivo (?<=…) — "lo que precede aquí coincide con X".
  • Lookbehind negativo (?<!…) — "lo que precede aquí no coincide con X".

La sintaxis de lookbehind simplemente inserta < tras el signo de interrogación. Un truco mnemotécnico útil — el ángulo apunta hacia atrás, hacia el texto ya consumido. Todo lo demás es idéntico al lookahead.

Lookahead: Coincidir por lo Que Viene Después

Supón que quieres el importe numérico de "50 dollars" pero no la palabra. Un \d+ ingenuo funciona, pero en cuanto también necesites excluir "50 euros" el lookahead se gana su sitio. El patrón \d+(?= dollars) coincide con "50" solo cuando le sigue el literal " dollars", pero esa palabra nunca forma parte de la coincidencia. Pégalo en el Probador de Regex contra "I paid 50 dollars and 30 euros" y verás un único resaltado sobre "50".

El lookahead negativo es el inverso y es donde el lookahead se vuelve genuinamente potente. Imagina extraer cada número que no sea un sufijo de versión. El patrón \d+(?!\.\d) coincide con dígitos no seguidos inmediatamente de un punto-y-dígito. Esta lógica de "coincide salvo que" es difícil de expresar de otra forma, porque regex no tiene un operador nativo de "pero no cuando" fuera del lookaround.

El Clásico: Reglas de Contraseña en un Solo Patrón

El uso real más común del lookahead es la validación compuesta. Una política de contraseña puede exigir al menos una minúscula, una mayúscula, un dígito y una longitud mínima de ocho. Cada requisito es un lookahead anclado independiente apilado al inicio:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$

Léelo como una lista de comprobación. El ^ ancla al inicio, luego cada (?=.*X) mira hacia delante por toda la cadena para confirmar que existe una clase — sin mover el cursor, de modo que la siguiente aserción arranca de nuevo desde la posición cero. Solo después de que pasen las tres, .{8,}$ consume realmente los caracteres e impone la longitud. Quita cualquier lookahead en el Probador de Regex y observa qué entradas empiezan a pasar; es la forma más rápida de sentir cómo cada aserción contribuye de forma independiente.

Lookbehind: Coincidir por lo Que Viene Antes

El lookbehind responde la pregunta especular. Para tomar los dígitos de un precio escrito "$50" sin capturar el símbolo de moneda, usa (?<=\$)\d+. La aserción confirma que hay un dólar inmediatamente a la izquierda, y la coincidencia contiene solo "50". Es más limpio que un grupo de captura porque no hay grupo que desreferenciar después — la coincidencia ya es exactamente lo que querías.

El lookbehind negativo es igual de práctico. Para encontrar cada aparición de "cat" que no esté precedida por "wild", escribe (?<!wild)cat. Contra "the cat near the wildcat" coincide con el primer "cat" y se salta el de dentro de "wildcat". Combinado con límites de palabra, el lookbehind negativo te deja tallar excepciones precisas que de otro modo exigirían filtrado posterior en el código.

Lookbehind de Longitud Variable: Un Superpoder de JavaScript

Aquí hay un detalle que sorprende a quien viene de otros lenguajes. Java y PCRE históricamente restringieron el lookbehind a longitud fija o acotada. El lookbehind de ES2018 en JavaScript no tiene tal restricción — la aserción dentro de (?<=…) puede coincidir con un número variable de caracteres. Eso significa que (?<=\$\d+\.)\d+ mira válidamente hacia atrás sobre una sucesión arbitraria de dígitos. Esta libertad viene de cómo V8 y SpiderMonkey ejecutan el lookbehind coincidiendo el patrón interno de derecha a izquierda, comportamiento descrito en la propuesta de lookbehind de TC39 que pasó a formar parte de ECMA-262. Si alguna vez te dijeron "el lookbehind debe ser de ancho fijo", esa regla simplemente no aplica al JavaScript moderno.

Lookahead y Lookbehind en Regex: Ejemplos Claros

Combinar Lookahead y Lookbehind: Extracción Quirúrgica

Las dos direcciones se componen. Para sacar un valor situado entre dos delimitadores — digamos el token dentro de key="value" — puedes flanquear la coincidencia con ambas aserciones: (?<=key=")[^"]*(?="). El lookbehind exige key=" a la izquierda, el lookahead exige una comilla de cierre a la derecha, y [^"]* en medio es el único texto consumido. El resultado es el valor desnudo, sin recortes.

Este patrón de "anclado por ambos lados, consume el centro" es uno de los modismos de lookaround más reutilizables. Aparece al raspar valores de atributos, cortar campos de líneas de log y aislar fragmentos dentro de cadenas estructuradas. Cuando la estructura circundante se vuelve genuinamente anidada o recursiva, sin embargo, detente — regex es la herramienta equivocada, y un analizador real como nuestra herramienta Consulta JSON Path es la adecuada para navegar datos en forma de árbol.

Insertar Separadores de Miles Sin Tocar el Número

Una demostración favorita del lookaround en sustitución es formatear un entero largo con comas. El patrón \B(?=(\d{3})+(?!\d)) coincide con las posiciones vacías donde va una coma, y luego reemplazas cada coincidencia por una coma. Funciona porque el lookahead afirma que sigue una sucesión de dígitos múltiplo de tres, el (?!\d) detiene la sucesión en el borde derecho y \B evita coincidir al inicio. Contra "1234567" la sustitución da "1,234,567". Abre el panel de sustitución del Probador de Regex, pon el reemplazo a una coma y recorre las coincidencias para ver iluminarse las posiciones de ancho cero una a una — es la ilustración más clara posible de que el lookaround coincide con lugares, no con caracteres.

Enmascarado y Redacción con Aserciones Negativas

Las transformaciones que preservan la privacidad se apoyan mucho en el lookaround. Para enmascarar todos menos los últimos cuatro dígitos de un número tipo tarjeta, coincides con cada dígito que tenga al menos cuatro dígitos más después: \d(?=\d{4}) con el flag global, reemplazando cada coincidencia por un asterisco. "4111111111111234" se convierte en "************1234". Sin grupos de captura, sin aritmética sobre longitudes de cadena — la aserción hace el conteo. El mismo enfoque enmascara correos, teléfonos e identificadores, todo enteramente en el navegador, de modo que el valor sensible nunca sale de tu máquina. Esa garantía del lado del cliente es justo por qué una herramienta que ejecutas localmente supera a pegar secretos en un servicio remoto.

Errores Que Confunden a Todos

  • Esperar que el lookaround consuma. Nunca lo hace. Si tu tabla de coincidencias muestra que el resaltado es más corto de lo esperado, es el comportamiento correcto — el texto afirmado se queda fuera de la coincidencia.
  • Lookaheads apilados y orden. Los lookaheads anclados como el ejemplo de contraseña arrancan todos desde la misma posición, así que su orden no afecta a la corrección — pero un .* faltante dentro de uno lo hará fallar en silencio, ya que la clase debe ser alcanzable desde donde está el cursor.
  • Capturar dentro de una aserción. Un grupo de captura puesto dentro de un lookahead, como el (\d{3}) de arriba, sigue poblando un grupo numerado aunque el lookahead sea de ancho cero. Esto es a veces útil y a veces una sorpresa cuando tus índices de grupo se desplazan.
  • Los runtimes antiguos carecen de lookbehind. El lookbehind lanza un error de sintaxis en motores anteriores a ES2018, incluidos Safari viejos y muchos entornos JavaScript embebidos. Detecta la función con un try/catch alrededor de new RegExp("(?<=a)b") antes de depender de ella en código de amplia distribución.
  • Rendimiento con lookahead anidado. Un lookahead con cuantificadores codiciosos aún puede retroceder mucho. Mantén el patrón interno lo más específico posible, la misma disciplina que evita el retroceso catastrófico en otros sitios.

Un Ejercicio de Cinco Minutos Que Puedes Hacer Ahora

La teoría se disuelve en cuanto los ves funcionar. Abre el Probador de Regex y recorre esta secuencia, editando un carácter a la vez. Empieza con \d+(?= dollars) sobre una frase de monedas mixtas. Cambia el lookahead a negativo y observa cómo se invierten las coincidencias. Añade un segundo lookahead apilado para construir un validador de contraseña desde cero. Convierte (?<=\$)\d+ de lookbehind positivo a negativo y predice el cambio antes de pulsar ejecutar. Finalmente, pega la sustitución de separadores de miles y recorre sus coincidencias de ancho cero.

Al terminar ese ejercicio los cuatro operadores dejan de ser símbolos abstractos y se convierten en herramientas que tomas deliberadamente. El lookahead pregunta por lo que hay delante, el lookbehind por lo que hay detrás, y la polaridad invierte la pregunta de "debe ser" a "no debe ser". Todo lo demás — reglas de contraseña, enmascarado, extracción por delimitadores, formateo de números — son solo esas cuatro aserciones compuestas con las clases de caracteres y cuantificadores corrientes que ya conoces. Para una cobertura más fundamental, nuestra guía completa de sintaxis de regex recorre los bloques básicos sobre los que se asienta el lookaround, y combina de forma natural con esta inmersión más profunda en las aserciones.

La recompensa se compone. Una vez que puedes leer un validador de lookaheads apilados de un vistazo, el patrón ingenioso de otra persona deja de ser un muro de puntuación y empieza a leerse como una frase — y escribirás los tuyos con la confianza tranquila de quien sabe exactamente dónde está parado el cursor.

← Volver al Blog