Expresiones regulares en la práctica
Las expresiones regulares tienen fama de ser de solo escritura: fáciles de producir, difíciles de releer y silenciosamente incorrectas de maneras que solo aparecen con datos reales. Casi todo eso nace de unos pocos malentendidos sobre lo que hace el motor. Esta guía los recorre y termina con los casos en los que lo correcto es guardar el patrón.
Qué está haciendo realmente el motor
Una expresión regular no describe la cadena que quieres: es un pequeño programa que el motor ejecuta en cada posición de la entrada, de izquierda a derecha. Intenta encajar desde el índice 0; si falla, pasa al índice 1 y vuelve a intentarlo, hasta que algo encaje o se acabe la entrada. Casi todos los resultados sorprendentes se explican por ese recorrido.
Por eso `\d{3}` encaja tan tranquilamente con "abc1234def": encontró "123" en el medio y nada en el patrón decía lo contrario. "Contiene tres dígitos" y "son exactamente tres dígitos" son preguntas distintas, y el patrón solo responde a la que hiciste.
Anclajes y límites de palabra
`^` y `$` atan el patrón al principio y al final de la entrada — o, con la bandera multilínea, al principio y al final de cada línea, una fuente discreta de validadores demasiado permisivos. `\b` es una posición de ancho cero entre un carácter de palabra y uno que no lo es, así que `\bcat\b` encuentra al animal en "the cat sat" pero no las letras dentro de "concatenate".
Para validar, ancla el patrón entero y prueba con los valores que quieres rechazar, no solo con los que quieres aceptar. Un validador que deja pasar todo lo bueno pero también la basura es peor que ninguno: traslada el fallo aguas abajo, donde el valor incorrecto es mucho más difícil de rastrear.
Ávido, perezoso y retroceso catastrófico
Los cuantificadores son ávidos por defecto: `.*` consume todo lo que puede y solo devuelve caracteres cuando el resto del patrón falla. Añadir `?` los vuelve perezosos. Sobre `<b>one</b> and <b>two</b>`, el patrón `<.*>` se traga la línea entera mientras que `<.*?>` se detiene en el primer `>` — la misma intención, un resultado completamente distinto.
Esa devolución es también donde muere el rendimiento. Cuantificadores anidados sobre conjuntos de caracteres solapados — `(a+)+b` es el caso de manual — pueden empujar al motor a probar un número exponencial de formas de partir la entrada antes de admitir que no hay coincidencia. Con texto suministrado por un atacante eso es una denegación de servicio, llamada ReDoS. Evita que los grupos cuantificados se solapen y prefiere una clase concreta antes que `.` siempre que puedas.
Clases de caracteres, el punto y Unicode
`.` significa "cualquier carácter salvo el salto de línea" salvo que actives la bandera dotall, y `\d`, `\w` y `\s` son ASCII-céntricos en la mayoría de implementaciones: `\w` excluye letras acentuadas y que `\d` incluya dígitos de otras escrituras depende del motor. Para texto que no sea ASCII puro, activa el modo Unicode y usa escapes de propiedad como `\p{L}` (cualquier letra) o `\p{N}` (cualquier número).
Los rangos dentro de una clase son rangos de puntos de código, y por eso `[A-z]` incluye en silencio los seis signos de puntuación que están entre `Z` y `a`. Escribe la clase que quieres decir. Y recuerda que un texto de aspecto idéntico puede ser una secuencia distinta: "é" como un único punto de código no encaja con un patrón pensado para "e" seguida de un acento combinante, así que normaliza antes de comparar.
Cuando la expresión regular es la herramienta equivocada
Los formatos anidados y con comillas — HTML, JSON, CSV, código fuente — no son lenguajes regulares. Un patrón puede mordisquearlos, pero cada delimitador entrecomillado y cada nivel de anidamiento añade otro caso especial, hasta que la expresión es ilegible y sigue fallando con la entrada que aún no has visto. Usa un analizador de verdad: para CSV, uno que respete las comillas; para HTML, el DOM.
Las direcciones de correo son la otra trampa clásica. La gramática de la especificación es mucho mayor que el patrón que la gente copia de internet, así que las expresiones de aspecto estricto rechazan a diario direcciones válidas — incluidas algunas tan corrientes como las que llevan un signo más o un dominio de primer nivel nuevo y largo. Comprueba que haya una `@` con algo plausible a cada lado y luego demuestra la dirección de la única forma que funciona: enviándole un correo.
- Encaja en la posición que quieres: ancla con `^`…`$` para validar, déjalo suelto para buscar.
- Prefiere `[^"]*` a `.*?` cuando conoces el delimitador: es más claro y no puede retroceder.
- Prueba con las entradas que esperas rechazar, no solo con las que esperas aceptar.
- Si el formato anida o entrecomilla, usa un analizador.