Los patrones como un lenguaje pequeño
Una expresión regular (regex) describe un conjunto de cadenas. En lugar de enumerar cada posibilidad, escribes un patrón: «tres dígitos», «una forma parecida a un correo», «líneas que empiezan por ERROR». Los lenguajes de programación, los editores y las herramientas de datos incorporan motores regex para buscar, validar y extraer texto.
Los dialectos de regex difieren (JavaScript, Python, PCRE, Rust). Esta guía se centra en conceptos compartidos por la mayoría de motores modernos, con énfasis en la sintaxis al estilo JavaScript usada en el navegador. Prueba patrones de forma interactiva con la herramienta de prueba regex.
Literales y metacaracteres
La mayoría de caracteres coinciden consigo mismos: cat coincide con las tres letras c-a-t en orden. Los metacaracteres tienen significado especial: . ^ $ * + ? ( ) [ ] { } \ | (y más según el dialecto).
Para hacer coincidir un metacaracter de forma literal, escápalo con una barra invertida: \. coincide con un punto. En algunos lenguajes, el escape de cadenas se apila sobre el escape de regex—provocando el «infierno de barras invertidas». Prefiere cadenas raw cuando el lenguaje las ofrezca.
Clases de caracteres
Los corchetes listan caracteres permitidos: [abc] coincide con a, b o c. Rangos como [0-9] coinciden con dígitos. La negación [^0-9] coincide con un carácter que no es un dígito.
Las clases abreviadas (dependen del flavor) incluyen \d (dígito), \w (carácter de palabra), \s (espacio en blanco). Sus definiciones exactas varían—sobre todo con Unicode. Cuando la validación deba ser precisa, prefiere rangos explícitos o escapes de propiedades Unicode si el motor los admite (\p{L} para letras en JS moderno).
Anclas
^ coincide con el inicio de una cadena (o de una línea en modo multilínea). $ coincide con el final. \b coincide con un límite de palabra. Las anclas no consumen caracteres; afirman posiciones.
^\d{5}$ coincide con una cadena que son exactamente cinco dígitos—no cinco dígitos enterrados en texto más largo—cuando se respetan las anclas.
Cuantificadores
Los cuantificadores especifican la repetición:
| Cuantificador | Significado |
|---|---|
* | cero o más |
+ | uno o más |
? | cero o uno |
{n} | exactamente n |
{n,} | n o más |
{n,m} | entre n y m inclusive |
Por defecto, los cuantificadores son codiciosos (greedy): coinciden con todo lo posible mientras el patrón global aún pueda tener éxito. Las variantes perezosas (*?, +?) coinciden con lo mínimo posible. El matching codicioso es una causa frecuente de sorpresas del tipo «mi patrón se comió todo el documento».
Grupos y alternancia
Los paréntesis ( ... ) crean grupos para cuantificar subpatrones y capturar subcadenas. (ab)+ coincide con ab, abab, etc. La alternancia | elige entre opciones: cat|dog.
Los grupos sin captura (?: ... ) agrupan sin guardar una captura—más limpio cuando solo necesitas estructura.
Las capturas con nombre existen en muchos motores ((?<year>\d{4})) y mejoran la legibilidad en extracciones.
Trampas codiciosas y backtracking
Un patrón clásico problemático para ciertas entradas parece (.*)+ o cuantificadores anidados ambiguos. El backtracking patológico puede congelar un proceso—ReDoS (regular expression denial of service). Para patrones suministrados por el usuario en producción, usa timeouts, parsers de subconjunto seguro o motores con garantías de tiempo lineal. Para tus propios patrones, prefiere clases de caracteres específicas frente a .* siempre que puedas.
Flags / modificadores
Flags habituales:
i— sin distinción de mayúsculas/minúsculasm—^/$se aplican por líneas— el punto coincide con saltos de línea (en motores que lo admiten)g— encontrar todas las coincidencias (global)u— modo Unicode en JavaScript
Los flags cambian el significado de forma sustancial; documenta siempre qué flags usa un validador.
Validación frente a extracción
La validación pregunta si toda la entrada coincide: a menudo combina un patrón con anclas de inicio y fin, o usa métodos de API con semántica de coincidencia completa. La extracción encuentra subcadenas: usa APIs de búsqueda/global y grupos de captura.
No finjas que un regex laxo de correo es un validador RFC completo. Para formatos críticos, combina regex con parsers dedicados.
Una pequeña escalera de aprendizaje
- Hacer coincidir una palabra fija.
- Añadir una clase de caracteres para un dígito.
- Cuantificar dígitos con
{n}. - Anclar el patrón.
- Introducir un grupo opcional.
- Extraer una captura.
- Solo entonces probar lookaheads/lookbehinds si tu motor los admite.
Saltar a un «regex perfecto de email» copiado de internet enseña poco y suele fallar en casos límite.
Hábitos de prueba
- Mantén una tabla de ejemplos que deben coincidir y que no deben coincidir.
- Incluye cadena vacía, longitud máxima y muestras Unicode.
- Prueba entradas multilínea cuando importen
mo el punto sobre saltos de línea. - Al depurar, simplifica el patrón hasta que desaparezca la coincidencia sorprendente, luego reconstruye.
La herramienta test-pattern te ayuda a iterar sobre ejemplos antes de fijar un patrón en el código de la aplicación.
Legibilidad y mantenimiento
Los regex largos son write-once, read-never. Estrategias:
- Dividir la validación en varias comprobaciones pequeñas.
- Usar modo verbose/extendido si está disponible (Python
re.X) con comentarios. - Asignar el patrón a una constante con nombre.
- Preferir parsers para estructuras anidadas (HTML, JSON)—regex es la herramienta equivocada para anidación arbitraria.
Lookaheads y lookbehinds (siguiente paso opcional)
Cuando anclas y grupos resulten cómodos, muchos motores ofrecen lookaheads y lookbehinds: aserciones que comprueban lo que sigue o precede a una posición sin consumir esos caracteres. Por ejemplo, un lookahead positivo puede exigir que una cadena tipo contraseña contenga un dígito en algún sitio sin mover el cursor de coincidencia principal de formas torpes. Estas funciones son potentes y fáciles de abusar; úsalas con moderación, coméntalas y verifica el comportamiento en tu dialecto exacto—el soporte de lookbehind y las reglas de ancho fijo no son idénticos en todas partes.
Resumen
Las expresiones regulares describen formas de texto con literales, clases, cuantificadores, anclas y grupos. Destacan en validaciones y extracciones concisas cuando los patrones se mantienen específicos y probados. Respeta las diferencias de dialecto, evita el backtracking catastrófico y pasa a parsers reales cuando la complejidad gramatical supera una sola línea de puntuación.