Expresiones regulares

Una expresión regular (o regex) es un patrón formal que describe un conjunto de cadenas de texto. Permite buscar, validar, extraer y transformar texto sin escribir bucles manuales de comparación carácter a carácter.

Ante problemas como "verifica que este texto es una dirección IP válida", "extrae todas las direcciones de correo de un fichero de logs de 50 MB" o "sustituye todos los nombres de variable que empiezan por _old_ en 3.000 ficheros de código", una regex lo resuelve en una sola línea. Están presentes en todos los lenguajes de programación modernos, en editores de texto, en terminales y en motores de bases de datos.

Anatomía

Una expresión regular se compone de elementos con roles bien definidos:

/patrón/flags — La notación estándar. Las barras / actúan de delimitadores; los flags controlan el comportamiento global: g (todas las coincidencias), i (insensible a mayúsculas), m (^/$ por línea), s (. incluye saltos de línea).

Metacaracteres — Símbolos con significado especial: . (cualquier carácter excepto \n), \d (un dígito), \w (letra, dígito o _), \s (espacio en blanco). Sus negaciones: \D, \W, \S.

Cuantificadores — Repeticiones: * (0 o más), + (1 o más), ? (0 o 1), {n} (exactamente n), {n,m} (entre n y m). Por defecto son greedy; añadir ? los convierte en lazy.

Anclas — Posiciones sin consumir caracteres: ^ (inicio), $ (final), \b (frontera de palabra).

Clases de caracteres[abc] coincide con a, b o c. [a-z] es un rango. [^abc] es la negación.

Grupos(...) agrupa y captura. (?:...) agrupa sin capturar. (?<nombre>...) crea capturas con nombre. (?=...) y (?!...) son lookaheads.

Alternacióngato|perro coincide con "gato" o "perro".

Historia y evolución

La teoría matemática que sustenta las expresiones regulares la formalizó el matemático Stephen Kleene en 1956. El paso de la teoría a la práctica lo dio Ken Thompson en 1968, al implementar las regex en el editor ed de UNIX. En 1973 creó grep —herramienta icónica de UNIX—, cuyo nombre proviene de la sintaxis regex: g/re/p (global regular expression print).

En los años 80, POSIX estandarizó las BRE y ERE, aún usadas en grep, sed y awk. El punto de inflexión fundamental llegó en 1987, cuando Larry Wall diseñó Perl con las regex como elemento central, creando las PCRE (Perl Compatible Regular Expressions), estándar de facto adoptado por PHP, Python, Ruby, Java y JavaScript.

En 1997, Philip Hazel publicó la biblioteca PCRE como implementación independiente. Hoy las PCRE2 están presentes en Apache, Nginx, PostgreSQL y prácticamente todas las herramientas del mundo digital.

Buenas prácticas

Prueba siempre con datos reales y casos límite. Una regex válida para 3 ejemplos puede fallar con datos reales imprevistos.

Ancla cuando sea posible. Usar ^ y $ reduce el tiempo de búsqueda y evita coincidencias parciales no previstas.

Evita el backtracking catastrófico. Patrones como (a+)+ pueden tardar tiempo exponencial y bloquear un servidor (ReDoS).

Usa grupos no capturadores (?:...) por defecto. Si no necesitas la captura, (?:...) es más eficiente y deja claro que el grupo es estructural.

Comenta las regex complejas. En Python y PHP el flag (?x) (verbose mode) permite añadir espacios y comentarios dentro del patrón.

Errores comunes

Olvidar escapar el punto. . significa "cualquier carácter", no un punto literal. Escribe \. para el punto literal.

Greedy vs lazy mal aplicado. <.*> sobre <b>texto</b> captura todo el fragmento. La versión lazy <.*?> captura cada etiqueta individualmente.

Olvidar el flag g. Sin g, string.match(/patrón/) en JavaScript devuelve solo la primera coincidencia.

Backtracking catastrófico. El patrón (a+)+b puede tardar tiempo exponencial en cadenas sin coincidencia. Explotable para bloquear servicios (ReDoS).

Asumir que . incluye saltos de línea. Por defecto no lo hace. Necesitas el flag s o usar [\s\S].

Usar regex para HTML o JSON. Es un antipatrón: frágil ante la anidación. Usa parsers especializados.

Casos de uso

Validación de formularios. Emails, teléfonos, códigos postales, DNI: las regex validan el formato en cliente y servidor simultáneamente.

Análisis de logs. Con regex puedes extraer IPs, códigos HTTP, timestamps o errores concretos de millones de líneas de log en cuestión de segundos.

Find & replace avanzado. VS Code, Vim y Sublime Text soportan regex en búsqueda/sustitución. Renombra 500 variables o reformatea fechas en un CSV de 100.000 filas con una sola operación.

Routing en frameworks web. Rails, Laravel, Django y Express definen sus rutas con patrones que capturan parámetros de la URL.

Procesado de datos y ETL. Las regex extraen campos de formatos no estructurados para normalizarlos y cargarlos en bases de datos.

Curiosidades

  • El nombre grep proviene del comando <code>:g/re/p</code> del editor <code>ed</code> de UNIX (1973): "global regular expression print". Su creación por Ken Thompson puso las regex al alcance de cualquier usuario UNIX.
  • El fenómeno ReDoS (Regular Expression Denial of Service) ha causado outages reales: en 2016, una regex con backtracking catastrófico bloqueó Stack Overflow durante 34 minutos en producción.
  • RFC 5322, el estándar formal de direcciones de correo electrónico, puede validarse completamente con una regex, pero el resultado tiene 6.318 caracteres. Para uso práctico, una regex de 50-100 caracteres cubre el 99,9% de los casos.
  • XKCD publicó el cómic #208 "Regular Expressions" en 2007. Es la referencia cultural central de la comunidad programadora para hablar de regex.