FormatFlow

Paso a paso · 6 min de lectura

Expresiones regulares: una guía práctica de inicio

Una expresión regular es un patrón que describe un conjunto de cadenas. Puede comprobar si un texto coincide, encontrar todas las apariciones, capturar partes de una coincidencia o buscar y reemplazar con referencias a esas capturas. La mayoría de los lenguajes de programación y muchas herramientas de línea de comandos implementan la misma sintaxis básica con pequeñas diferencias.

La dificultad no está en escribir un patrón una vez, sino en entender por qué un patrón coincide más o menos de lo que pretendías. Esta guía cubre los bloques de construcción, el modelo de coincidencia que explica resultados sorprendentes y los límites de seguridad que conviene conocer antes de ejecutar un patrón sobre entrada no confiable.

Una expresión regular es una descripción, no una cadena de búsqueda

Una búsqueda literal encuentra los caracteres exactos que escribiste. Una expresión regular interpreta algunos caracteres como instrucciones, así que el patrón abc coincide con los caracteres abc, mientras que a.c coincide con cualquier cadena de tres caracteres que empiece por a y termine por c. Esa interpretación es lo que hace potente a regex y lo que convierte un punto sin escapar en un error habitual.

Las expresiones regulares suelen aplicarse a una línea o a una cadena completa según los flags, y ese contexto cambia el resultado. El mismo patrón puede coincidir con una subcadena en una sola línea y con algo completamente distinto una vez incluidos los saltos de línea. Confirma siempre si el motor trata la entrada como una sola cadena o como líneas separadas antes de depurar el patrón en sí.

Los bloques de construcción que conviene aprender primero

Las clases de caracteres coinciden con un carácter de un conjunto: [abc] coincide con a, b o c; [a-z] coincide con cualquier letra ASCII minúscula; \d es un dígito; \w es un carácter de palabra; \s es espacio en blanco. Las clases negadas invierten el significado, así que [^0-9] coincide con cualquier cosa que no sea un dígito. Los anclajes no consumen caracteres: ^ coincide con el inicio de la cadena o de la línea y $ con el final.

Los cuantificadores indican cuántas veces se repite el elemento anterior: * significa cero o más, + significa uno o más, ? significa cero o uno, y {2,5} significa entre dos y cinco. Por defecto son codiciosos y toman lo máximo posible, y solo devuelven caracteres si el resto del patrón los necesita; añadir ? los hace perezosos y toman lo mínimo posible. Los grupos entre paréntesis capturan lo que coincidió, y una barra vertical crea alternativas como cat|dog.

  • \d+ coincide con uno o más dígitos; ^\d{5}$ coincide exactamente con cinco dígitos por sí solo.
  • \bword\b coincide con la palabra completa, no con la palabra dentro de otra palabra.
  • ([A-Za-z]+)\s+([A-Za-z]+) captura dos palabras separadas por espacio en blanco.
  • a.*?b coincide desde la primera a hasta la b más cercana, mientras que a.*b llega hasta la última b.
  • Los flags cambian el comportamiento: i ignora mayúsculas y minúsculas, g encuentra todas las coincidencias, m trata ^ y $ como anclajes de línea, s permite que el punto coincida con saltos de línea y u activa la semántica Unicode completa.

Cómo avanza realmente la coincidencia

Los motores prueban el patrón en posiciones sucesivas de la entrada (salvo que esté anclado), y en cada posición exploran alternativas. Cuando un cuantificador codicioso ha consumido caracteres y el resto del patrón falla, el motor retrocede y prueba una repetición más corta. Ese retroceso es la razón por la que un patrón puede coincidir correctamente y aun así ser lento: el número de caminos que explora puede crecer de forma exponencial con la entrada.

La coincidencia global es un bucle alrededor de ese proceso. Un patrón con el flag g devuelve coincidencias sucesivas, y las coincidencias de longitud cero avanzan la posición de forma especial para evitar un bucle infinito. Los grupos de captura se numeran por el orden en que aparece su paréntesis de apertura, y los grupos con nombre hacen que los patrones complejos sean mucho más fáciles de leer y mantener.

Un flujo de trabajo de depuración que funciona

Empieza por la entrada más pequeña que debería coincidir y por la entrada más cercana que no debería. Prueba ambas y después añade complejidad un elemento a la vez en lugar de escribir el patrón completo y quedarte mirando el resultado. Cuando una coincidencia es incorrecta, hazte tres preguntas: dónde empezó, dónde terminó y qué alternativa o repetición consumió los caracteres intermedios.

Escapa los caracteres que el motor trata de forma especial. Esta es la causa más común de confusión al probar URL, rutas de archivo, direcciones de correo y fragmentos de código. Recuerda que los literales de cadena de JSON y de los lenguajes de programación también procesan barras invertidas, así que un patrón escrito para un motor regex puede necesitar la barra invertida duplicada en el código fuente. Usa un probador que muestre tanto el patrón que escribiste como el patrón que recibió el motor.

Seguridad: backtracking catastrófico y entrada no confiable

Algunos patrones son correctos pero catastróficamente lentos con entradas concretas. Los cuantificadores anidados como (a+)+$ son el ejemplo clásico: para una secuencia larga de caracteres seguida de uno que no puede coincidir con el anclaje final, el motor prueba un número exponencial de formas de dividir la secuencia. Las defensas prácticas son simplificar la repetición anidada, anclar los patrones cuando sea posible, preferir clases de caracteres explícitas y aplicar un tiempo de espera o un límite de longitud de entrada al hacer coincidir texto no confiable.

Nunca uses una expresión regular como única defensa para análisis sensibles a la seguridad. Las direcciones de correo, el HTML, las URL y los lenguajes de programación superan lo que un patrón compacto puede validar correctamente. Usa regex para una comprobación rápida de cordura y después analiza con una biblioteca dedicada o valida estructuralmente. Y cuando un patrón se ejecuta en un servidor, limita el tamaño de la entrada y el número de coincidencias para que una sola petición no pueda consumir el proceso.

Preguntas frecuentes

¿Por qué mi regex solo coincide con la primera aparición?
La mayoría de los métodos de cadena devuelven solo la primera coincidencia. Añade el flag g cuando uses un motor que lo admita, o usa una función de búsqueda global como matchAll. El probador muestra todas las coincidencias por defecto, así que si él encuentra varias y tu código una, el flag suele ser la diferencia.
¿Cuál es la diferencia entre cuantificadores codiciosos y perezosos?
Los cuantificadores codiciosos consumen lo máximo posible y después retroceden; los perezosos consumen lo mínimo posible y se expanden solo cuando hace falta. Añadir un signo de interrogación después del cuantificador lo hace perezoso: a.*b llega hasta la última b de la línea, mientras que a.*?b se detiene en la primera b.
¿Por qué mi patrón funciona en un lenguaje y falla en otro?
Los dialectos de expresiones regulares difieren en las funciones admitidas y en los valores por defecto. El lookbehind, la sintaxis de captura con nombre, los escapes de propiedades Unicode y el significado de \w varían según el motor. Revisa también cómo se pasa el patrón: el escape de JSON o de cadenas puede cambiar las barras invertidas antes de que el motor las vea.
¿Cómo hago para coincidir a través de varias líneas?
Por defecto, el punto no coincide con un salto de línea. Activa el flag s para que el punto coincida con saltos de línea, y usa el flag m si quieres que ^ y $ coincidan en cada límite de línea en lugar de solo al principio y al final de la cadena completa. Ambos flags están disponibles en JavaScript y en muchos otros motores.
¿Basta una regex para validar una dirección de correo o una URL?
No. Una regex puede detectar errores obvios, pero la validación completa requiere analizar con una biblioteca que implemente la especificación real. Usa un patrón permisivo para rechazar entradas claramente inválidas y deja que el analizador real decida si el valor es utilizable.

Herramientas para esta tarea

Todas las herramientas Desarrollo

Revisado por FormatFlow Editorial. Las herramientas y guías detalladas siguen en inglés hasta que se complete la traducción del resto del sitio.