Expresiones Regulares: Una Guía Práctica con Ejemplos

· 12 min de lectura

Las expresiones regulares (regex) son una de las herramientas más poderosas en el kit de un desarrollador, sin embargo, a menudo son malinterpretadas o evitadas por completo. Ya sea que estés validando entrada de usuario, analizando archivos de registro o transformando datos de texto, regex proporciona una forma concisa y eficiente de hacer coincidir patrones en cadenas.

Esta guía completa te llevará desde los conceptos básicos de regex hasta técnicas avanzadas, con ejemplos prácticos que puedes usar inmediatamente en tus proyectos. Al final, entenderás no solo cómo funciona regex, sino cuándo y por qué usarlo.

Tabla de Contenidos

¿Qué es Regex y Por Qué Debería Importarte?

Una expresión regular es una secuencia de caracteres que define un patrón de búsqueda. Piensa en ella como un mini-lenguaje diseñado específicamente para hacer coincidir patrones en texto. En lugar de buscar cadenas exactas, regex te permite describir patrones como "cualquier dirección de correo electrónico" o "todos los números de teléfono en este formato".

Regex es compatible con prácticamente todos los lenguajes de programación y muchas herramientas de línea de comandos. Una vez que aprendes la sintaxis, puedes aplicarla en todas partes—desde JavaScript y Python hasta grep y sed.

Los casos de uso comunes incluyen:

Consejo profesional: Aunque regex es poderoso, no siempre es la herramienta correcta. Para tareas de análisis complejas como HTML o JSON, usa analizadores dedicados en su lugar. Regex funciona mejor para patrones bien definidos y relativamente simples.

Conceptos Básicos de Regex: Bloques de Construcción

Cada patrón regex se construye a partir de bloques de construcción fundamentales. Entender estos elementos centrales es esencial antes de pasar a patrones más complejos.

Caracteres Literales

El regex más simple es solo texto literal. El patrón cat coincide con la cadena exacta "cat" en tu texto. La mayoría de los caracteres alfanuméricos coinciden directamente consigo mismos.

Metacaracteres

Ciertos caracteres tienen significados especiales en regex. Estos se llaman metacaracteres e incluyen: . ^ $ * + ? { } [ ] \ | ( )

Para hacer coincidir estos caracteres literalmente, necesitas escaparlos con una barra invertida. Por ejemplo, \. coincide con un punto literal.

El Comodín de Punto

El punto . es el comodín más básico—coincide con cualquier carácter individual excepto nueva línea. El patrón a.c coincide con "abc", "a1c", "a-c", pero no con "ac" (sin carácter entre) o "a\nc" (nueva línea).

Patrón Coincide Ejemplo
. Cualquier carácter (excepto nueva línea) a.c coincide con abc, a1c, a-c
\d Cualquier dígito [0-9] \d{3} coincide con 123, 456
\w Carácter de palabra [a-zA-Z0-9_] \w+ coincide con hello, user_1
\s Espacio en blanco (espacio, tabulación, nueva línea) \s+ coincide con espacios, tabulaciones
\D No dígito \D+ coincide con abc, xyz
\W Carácter que no es de palabra \W+ coincide con !@#, espacios
\S No espacio en blanco \S+ coincide con cualquier texto visible

Observa que las versiones en mayúscula (\D, \W, \S) son el inverso de sus contrapartes en minúscula. Este es un patrón común en la sintaxis de regex.

Cuantificadores: Controlando la Repetición

Los cuantificadores especifican cuántas veces debe repetirse un patrón. Se colocan después del elemento que deseas repetir y son fundamentales para crear patrones flexibles.

Cuantificadores Básicos

Cuantificador Significado Ejemplo
* 0 o más veces ab*c coincide con ac, abc, abbc, abbbc
+ 1 o más veces ab+c coincide con abc, abbc (no ac)
? 0 o 1 vez (opcional) colou?r coincide con color, colour
{n} Exactamente n veces \d{4} coincide con 2026, 1999
{n,} n o más veces \d{3,} coincide con 123, 1234, 12345
{n,m} Entre n y m veces \d{2,4} coincide con 12, 123, 1234

Coincidencia Codiciosa vs. Perezosa

Por defecto, los cuantificadores son codiciosos—coinciden con tanto texto como sea posible. Esto puede llevar a resultados inesperados al hacer coincidir patrones como etiquetas HTML.

// Coincidencia codiciosa
const text = "<div>Hello</div><div>World</div>";
const greedy = /<.*>/;
// Coincide: "<div>Hello</div><div>World</div>" (¡cadena completa!)

// Coincidencia perezosa
const lazy = /<.*?>/;
// Coincide: "<div>" (se detiene en el primer corchete de cierre)

Agregar ? después de un cuantificador lo hace perezoso (no codicioso). Los cuantificadores perezosos coinciden con tan poco texto como sea posible mientras aún satisfacen el patrón.

Consejo rápido: Al hacer coincidir contenido entre delimitadores (comillas, corchetes, etiquetas), los cuantificadores perezosos son generalmente lo que quieres. Usa .*? en lugar de .* para evitar coincidir demasiado.

Clases de Caracteres y Atajos

Las clases de caracteres te permiten hacer coincidir cualquier carácter de un conjunto específico. Se definen usando corchetes y son increíblemente útiles para crear patrones flexibles.

Clases de Caracteres Básicas

// Coincidir cualquier vocal
/[aeiou]/

// Coincidir cualquier dígito
/[0-9]/

// Coincidir cualquier letra minúscula
/[a-z]/

// Coincidir cualquier letra (sin distinción de mayúsculas)
/[a-zA-Z]/

// Coincidir caracteres alfanuméricos
/[a-zA-Z0-9]/

Clases de Caracteres Negadas

Usa ^ al inicio de una clase de caracteres para negarla—coincidiendo con cualquier carácter excepto los listados.

// Coincidir cualquier no dígito
/[^0-9]/

// Coincidir cualquier no vocal
/[^aeiou]/

// Coincidir cualquier carácter excepto espacio o tabulación
/[^ \t]/

Caracteres Especiales en Clases

La mayoría de los metacaracteres pierden su significado especial dentro de las clases de caracteres. Puedes incluir ., *, + y ? sin escaparlos. Sin embargo, aún necesitas escapar ], \, ^ y - en ciertas posiciones.

// Coincidir un punto o coma
/[.,]/

// Coincidir un guion (escapar o colocar al inicio/final)
/[-a-z]/ o /[a-z-]/

// Coincidir un corchete de cierre (debe escaparse)
/[\]]/

Grupos y Capturas

Los grupos sirven para dos propósitos principales: te permiten aplicar cuantificadores a múltiples caracteres, y capturan texto coincidente para uso posterior.

Grupos de Captura

Los paréntesis crean grupos de captura que recuerdan el texto coincidente. Esto es esencial para extraer datos de cadenas.

// Extraer componentes de fecha
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2026-03-29".match(datePattern);

// match[0]: "2026-03-29" (coincidencia completa)
// match[1]: "2026" (primer grupo)
// match[2]: "03" (segundo grupo)
// match[3]: "29" (tercer grupo)

Grupos de Captura Nombrados

Los grupos nombrados hacen tu regex más legible y tu código más mantenible. En lugar de referirte a grupos por número, les das nombres descriptivos.

// Sintaxis de grupos nombrados: (?<name>pattern)
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = "2026-03-29".match(datePattern);

// Acceder por nombre
console.log(match.groups.year);  // "2026"
console.log(match.groups.month); // "03"
console.log(match.groups.day);   // "29"

Grupos sin Captura

A veces necesitas agrupar para cuantificadores o alternancia pero no quieres capturar el texto. Los grupos sin captura usan la sintaxis (?:...).

// Capturar el protocolo sin crear un grupo
/(?:https?|ftp):\/\/([a-z.]+)/

// Esto crea solo un grupo de captura (el dominio)
// El grupo de protocolo (?:https?|ftp) no captura

Los grupos sin captura son más rápidos y usan menos memoria que los grupos de captura. Úsalos cuando no necesites el texto capturado.

Referencias Inversas

Las referencias inversas te permiten hacer coincidir el mismo texto que fue capturado por un grupo anterior. Esto es útil para encontrar palabras repetidas o hacer coincidir delimitadores emparejados.

// Encontrar palabras repetidas
/\b(\w+)\s+\1\b/
// Coincide con "the the" o "hello hello"

// Coincidir comillas emparejadas
/(['"])(.*?)\1/
// Coincide con "hello" o 'world' pero no "mixed'

Alternancia

El operador de barra vertical | crea alternancia—coincidiendo con un patrón u otro. Es como un OR lógico.

// Coincidir cat, dog o bird
/cat|dog|bird/

// Coincidir extensiones de archivo comunes
/\.(jpg|jpeg|png|gif|webp)$/i

// Coincidir Mr., Mrs., Ms. o Dr.
/(?:Mr|Mrs|Ms|Dr)\./

Anclas y Límites

Las anclas no coinciden con caracteres—coinciden con posiciones en la cadena. Son esenciales para asegurar que los patrones aparezcan en ubicaciones específicas.

Anclas de Cadena

// Debe comenzar con "Hello"
/^Hello/

// Debe terminar con "world"
/world$/

// La cadena completa debe ser exactamente 5 dígitos
/^\d{5}$/

Límites de Palabra

El ancla \b coincide con límites de palabra—posiciones entre caracteres de palabra y no palabra. Esto es crucial para hacer coincidir palabras completas.

// Coincidir "cat" como palabra completa
/\bcat\b/
// Coincide: "cat", "the cat sat"
// No coincide: "category", "scat"

// Coincidir palabras que comienzan con "pre"
/\bpre\w+/
// Coincide: "preview", "prepare", "prefix"

El inverso \B coincide con no límites de palabra—posiciones donde ambos lados son caracteres de palabra o ambos son caracteres que no son de palabra.

Consejo profesional: Siempre usa límites de palabra al buscar palabras completas. Sin ellos, buscar "cat" también coincidirá con "category" y "concatenate". El patrón \bcat\b asegura que solo coincidas con la palabra completa.

Patrones Comunes para Uso en el Mundo Real

Aquí hay patrones regex probados en batalla para tareas comunes de validación y extracción. Estos patrones equilibran simplicidad con precisión práctica.

Tipo de Patrón Regex Notas
Email (simple) ^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$ Bueno para validación básica
Email (compatible con RFC) ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ Más estricto, ampliamente aceptado
URL ^https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/\S*)?$ URLs HTTP/HTTPS básicas
Dirección IPv4 ^(?:\d{1,3}\.){3}\d{1,3}$ Solo formato, no valida rangos
IPv4 (estricto) ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ Valida rango 0-255
Fecha (AAAA-MM-DD) ^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ Formato ISO 8601
Hora (24 horas) ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$ HH:MM o HH:MM:SS
Teléfono (EE.UU.) ^\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$ Formato flexible
Color Hex ^#(?:[0-9a-fA-F]{3}){1,2}$ Códigos hex de 3 o 6 dígitos
Tarjeta de Crédito ^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$ Solo formato, usa Luhn para validación
Nombre de Usuario ^[a-zA-Z0-9_-]{3,16}$ 3-16 caracteres, alfanumérico más _ y -
Slug ^[a-z0-9]+(?:-[a-z0-9]+)*$ Minúsculas amigables para URL con guiones

Validación de Contraseña

La validación de contraseña requiere verificar múltiples condiciones simultáneamente. Las aserciones de búsqueda anticipada hacen esto posible sin lógica compleja.

// Contraseña fuerte: 8+ caracteres, mayúscula, minúscula, dígito, carácter especial
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/

// Desglosándolo:
// (?=.*[a-z])     - al menos una letra minúscula
// (?=.*[A-Z])     -