Como usar expresiones regulares (regex): guia completa para desarrolladores
Aprende expresiones regulares desde cero. Sintaxis basica, clases de caracteres, cuantificadores, grupos, lookahead, lookbehind y patrones comunes para email, telefono, URL e IP. Con ejemplos practicos.
Que son las expresiones regulares y para que sirven
Las expresiones regulares (regex o regexp) son patrones de busqueda que permiten encontrar, validar y manipular texto de forma extremadamente precisa. Son una herramienta fundamental en la programacion, la administracion de sistemas y el procesamiento de datos.
Una expresion regular es esencialmente una secuencia de caracteres que define un patron de busqueda. Con una sola linea de regex puedes hacer lo que de otra forma requeriria docenas de lineas de codigo condicional.
Usos comunes de las expresiones regulares:
- Validacion de datos: Verificar que un email, telefono, URL o codigo postal tenga el formato correcto
- Busqueda y reemplazo: Encontrar patrones en textos largos y reemplazarlos (como en editores de texto o IDEs)
- Extraccion de datos: Sacar informacion especifica de textos no estructurados (web scraping, logs)
- Parsing de logs: Analizar archivos de registro de servidores y aplicaciones
- Linting y formateo: Verificar que el codigo sigue ciertas convenciones
- Routing en frameworks web: Definir patrones de URL en Express, Django, Rails, etc.
Las regex estan disponibles en practicamente todos los lenguajes de programacion: JavaScript, Python, Java, C#, PHP, Ruby, Go, Rust, y muchos mas. Tambien se usan en herramientas de linea de comandos como grep, sed y awk.
Si quieres practicar mientras lees esta guia, abre nuestra herramienta de prueba regex en otra pestana.
Sintaxis basica: caracteres literales y metacaracteres
La sintaxis de regex se divide en dos tipos de caracteres: literales (que se buscan tal cual) y metacaracteres (que tienen un significado especial).
Caracteres literales:
Las letras, numeros y la mayoria de simbolos se buscan literalmente. El patron gato encuentra la palabra "gato" en el texto.
Los metacaracteres fundamentales:
| Metacaracter | Significado | Ejemplo | Coincide con |
|---|---|---|---|
. | Cualquier caracter (excepto salto de linea) | g.to | "gato", "gito", "g3to" |
^ | Inicio de linea/cadena | ^Hola | "Hola mundo" (solo al inicio) |
$ | Fin de linea/cadena | mundo$ | "Hola mundo" (solo al final) |
* | 0 o mas repeticiones | ab*c | "ac", "abc", "abbc", "abbbc" |
+ | 1 o mas repeticiones | ab+c | "abc", "abbc" (no "ac") |
? | 0 o 1 repeticion (opcional) | colou?r | "color", "colour" |
| | Alternativa (OR) | gato|perro | "gato" o "perro" |
\ | Escape (literal del siguiente caracter) | \. | Un punto literal |
Escapar metacaracteres:
Si necesitas buscar un metacaracter como caracter literal, debes escaparlo con \. Por ejemplo:
\.busca un punto literal (no "cualquier caracter")\*busca un asterisco literal\?busca un signo de interrogacion literal\(y\)buscan parentesis literales\\busca una barra invertida literal
Ejemplo practico: Para buscar la cadena "precio: $9.99" necesitas: precio: \$9\.99
Clases de caracteres y clases predefinidas
Las clases de caracteres (character classes) te permiten definir un conjunto de caracteres que son validos en una posicion especifica del patron.
Clases personalizadas con corchetes [ ]:
| Patron | Significado | Ejemplo de coincidencia |
|---|---|---|
[abc] | Cualquiera de: a, b o c | "a", "b", "c" |
[a-z] | Cualquier letra minuscula | "a", "m", "z" |
[A-Z] | Cualquier letra mayuscula | "A", "M", "Z" |
[0-9] | Cualquier digito | "0", "5", "9" |
[a-zA-Z] | Cualquier letra | "a", "Z", "m" |
[a-zA-Z0-9] | Cualquier alfanumerico | "a", "3", "Z" |
[^abc] | Cualquiera EXCEPTO a, b, c | "d", "1", "Z" |
[^0-9] | Cualquiera que NO sea digito | "a", "!", " " |
Clases predefinidas (shorthand):
Las clases predefinidas son atajos para combinaciones comunes:
| Atajo | Equivalente | Significado |
|---|---|---|
\d | [0-9] | Cualquier digito |
\D | [^0-9] | Cualquiera que NO sea digito |
\w | [a-zA-Z0-9_] | Cualquier caracter de palabra (alfanumerico + guion bajo) |
\W | [^a-zA-Z0-9_] | Cualquiera que NO sea caracter de palabra |
\s | [\t\n\r\f\v ] | Cualquier espacio en blanco |
\S | [^\t\n\r\f\v ] | Cualquiera que NO sea espacio en blanco |
\b | (sin equivalente directo) | Limite de palabra (word boundary) |
Limite de palabra (\b):
El \b es especialmente util para buscar palabras completas. \bgato\b encuentra "gato" pero NO "gatouno" ni "ungato". Es un ancla de posicion, no consume caracteres.
Ejemplo practico: Para validar que una cadena contiene solo letras, numeros y guiones: ^[a-zA-Z0-9-]+$
Cuantificadores y modificadores de repeticion
Los cuantificadores especifican cuantas veces debe aparecer el elemento que los precede.
Cuantificadores basicos:
| Cuantificador | Significado | Ejemplo | Coincide con |
|---|---|---|---|
* | 0 o mas veces | \d* | "", "5", "123", "99999" |
+ | 1 o mas veces | \d+ | "5", "123", "99999" (no "") |
? | 0 o 1 vez | -?\d+ | "42", "-42" |
{n} | Exactamente n veces | \d{4} | "2026", "1234" (exactamente 4 digitos) |
{n,} | n o mas veces | \d{2,} | "12", "123", "1234" (2+ digitos) |
{n,m} | Entre n y m veces | \d{2,4} | "12", "123", "1234" (2 a 4 digitos) |
Cuantificadores greedy vs lazy:
Por defecto, los cuantificadores son greedy (codiciosos): intentan coincidir con la mayor cantidad de texto posible. Al agregar ? despues del cuantificador, se vuelven lazy (perezosos): coinciden con la menor cantidad posible.
Ejemplo de la diferencia:
Texto: <b>Hola</b> y <b>Mundo</b>
<b>.*</b>(greedy): coincide con<b>Hola</b> y <b>Mundo</b>(todo)<b>.*?</b>(lazy): coincide con<b>Hola</b>y<b>Mundo</b>(por separado)
La diferencia es crucial cuando trabajas con HTML, XML o cualquier texto con delimitadores repetidos. El modo lazy es casi siempre lo que quieres cuando buscas pares de etiquetas o delimitadores.
Ejemplo practico: Validar un codigo postal de 5 digitos con guion opcional y 4 digitos extras (formato US): ^\d{5}(-\d{4})?$
Esto coincide con "12345" y "12345-6789" pero no con "1234" ni "123456".
Grupos de captura y referencias
Los grupos permiten agrupar partes de un patron, capturar el texto coincidente para usarlo despues, y aplicar cuantificadores a subexpresiones completas.
Tipos de grupos:
| Sintaxis | Tipo | Descripcion |
|---|---|---|
(patron) | Grupo de captura | Agrupa y captura el texto coincidente |
(?:patron) | Grupo sin captura | Agrupa pero NO captura (mas eficiente) |
(?<nombre>patron) | Grupo con nombre | Captura con un nombre identificable |
\1, \2 | Referencia hacia atras | Referencia al texto capturado por grupo 1, 2, etc. |
Grupo de captura basico:
Para extraer el ano, mes y dia de una fecha formato YYYY-MM-DD:
(\d{4})-(\d{2})-(\d{2})
- Grupo 1: Ano (ej: "2026")
- Grupo 2: Mes (ej: "03")
- Grupo 3: Dia (ej: "16")
En JavaScript: "2026-03-16".match(/(\d{4})-(\d{2})-(\d{2})/) devuelve un array donde [1] es "2026", [2] es "03" y [3] es "16".
Grupos con nombre (named groups):
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
En JavaScript: match.groups.year, match.groups.month, match.groups.day
Referencias hacia atras (backreferences):
Permiten referirse al texto exacto capturado por un grupo anterior:
(\w+)\s+\1encuentra palabras duplicadas ("el el", "la la", "the the")(['"])(.*?)\1encuentra texto entre comillas, asegurando que las comillas de apertura y cierre coincidan
Alternativa dentro de grupos:
(https?|ftp):// coincide con "http://", "https://" o "ftp://"
Prueba estos patrones en tiempo real con nuestra herramienta regex.
Lookahead y lookbehind: aserciones de posicion
Los lookahead y lookbehind son aserciones que verifican si un patron existe antes o despues de la posicion actual, sin consumir caracteres. Son extremadamente poderosos para validaciones complejas.
Los 4 tipos de aserciones:
| Sintaxis | Nombre | Significado |
|---|---|---|
(?=patron) | Positive lookahead | Lo que sigue DEBE coincidir con el patron |
(?!patron) | Negative lookahead | Lo que sigue NO debe coincidir con el patron |
(?<=patron) | Positive lookbehind | Lo que precede DEBE coincidir con el patron |
(?<!patron) | Negative lookbehind | Lo que precede NO debe coincidir con el patron |
Ejemplo 1: Validar contrasena robusta
Una contrasena que requiera al menos una mayuscula, una minuscula, un digito y 8+ caracteres:
^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$
(?=.*[A-Z]): Lookahead positivo - debe contener al menos una mayuscula(?=.*[a-z]): Debe contener al menos una minuscula(?=.*\d): Debe contener al menos un digito.{8,}: Debe tener 8 o mas caracteres
Ejemplo 2: Encontrar precios sin el simbolo de moneda
(?<=\$)\d+\.\d{2}
En el texto "El precio es $29.99 y el envio $5.00", captura "29.99" y "5.00" pero no el "$".
Ejemplo 3: Encontrar palabras que NO sean seguidas por cierto patron
\w+(?!\s*:)
Encuentra palabras que NO son seguidas por dos puntos. Util para distinguir entre claves y valores en textos tipo "clave: valor".
Ejemplo 4: Numeros NO precedidos por guion
(?<!-)\b\d+\b
Encuentra numeros positivos ignorando los negativos. En "5 -3 8 -12", encuentra "5" y "8" pero no "3" ni "12".
Nota de compatibilidad: Los lookbehind no estan soportados en todos los sabores de regex. JavaScript los soporta desde ES2018. Python, Java, C# y .NET los soportan completamente. Algunos sabores limitan los lookbehind a patrones de longitud fija.
Patrones comunes: email, telefono, URL e IP
Estas son expresiones regulares probadas para los patrones de validacion mas comunes. Recuerda que ninguna regex es 100% perfecta para formatos complejos como email; para produccion, complementa con validacion del servidor.
1. Email (validacion practica):
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
- Parte local: letras, numeros, puntos, guiones, guion bajo, %, +
- @: separador obligatorio
- Dominio: letras, numeros, puntos, guiones
- TLD: al menos 2 letras
- Valida: user@example.com, nombre.apellido@empresa.co.uk
2. Telefono internacional (formato E.164):
^\+?[1-9]\d{1,14}$
- + opcional al inicio
- Primer digito: 1-9 (no puede empezar con 0)
- Hasta 15 digitos en total
- Valida: +573001234567, 12025551234
3. URL (HTTP/HTTPS):
^https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/[\w.~:/?#\[\]@!$&'()*+,;=-]*)?$
- Protocolo: http:// o https://
- Dominio: alfanumerico con puntos y guiones
- TLD: al menos 2 letras
- Path: cualquier caracter valido de URL (opcional)
4. Direccion IPv4:
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$
- 4 octetos separados por puntos
- Cada octeto: 0-255
- Valida: 192.168.1.1, 10.0.0.1, 255.255.255.0
- Rechaza: 256.1.1.1, 192.168.1.999
5. Fecha formato ISO (YYYY-MM-DD):
^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$
- Ano: 4 digitos
- Mes: 01-12
- Dia: 01-31
- No valida dias invalidos (como 02-30), para eso necesitas logica adicional
6. Hexadecimal de color CSS:
^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
- Formatos: #RGB, #RRGGBB, #RRGGBBAA
- Valida: #fff, #FF5733, #FF573380
Prueba y ajusta todos estos patrones en nuestra herramienta de prueba regex. Para validar datos JSON que contengan estos patrones, usa nuestro validador JSON.
Flags, rendimiento y buenas practicas
Para dominar regex necesitas conocer los flags (modificadores) y seguir buenas practicas que eviten problemas de rendimiento y mantenibilidad.
Flags comunes:
| Flag | Nombre | Efecto |
|---|---|---|
g | Global | Encuentra TODAS las coincidencias, no solo la primera |
i | Case insensitive | No distingue mayusculas de minusculas |
m | Multiline | ^ y $ coinciden con inicio/fin de cada LINEA, no solo de la cadena |
s | Dotall | El punto (.) tambien coincide con saltos de linea |
u | Unicode | Soporte completo para caracteres Unicode |
En JavaScript: /patron/flags - ejemplo: /hola mundo/gi
En Python: re.compile(r'patron', re.IGNORECASE | re.MULTILINE)
Buenas practicas de rendimiento:
- Evita el backtracking catastrofico: Patrones como
(a+)+$pueden causar que el motor de regex pruebe una cantidad exponencial de combinaciones. Esto se conoce como ReDoS (Regular Expression Denial of Service). Usa cuantificadores posesivos (++) o grupos atomicos cuando esten disponibles - Se especifico:
[a-z]+es mejor que.+cuando solo esperas letras. Cuanto mas especifico sea tu patron, mas rapido sera - Usa anclas:
^y$le dicen al motor donde empezar y terminar, evitando busquedas innecesarias - Prefiere grupos sin captura:
(?:...)es mas eficiente que(...)cuando no necesitas capturar - Compila la regex si la usas repetidamente: En Python usa
re.compile(), en Java usaPattern.compile()
Buenas practicas de mantenibilidad:
- Comenta tus regex: En Python puedes usar el flag
re.VERBOSEpara agregar comentarios y espacios legibles - Divide patrones complejos: En lugar de una regex monolitica, divide en partes y combinalas programaticamente
- Escribe tests: Siempre escribe casos de prueba tanto para coincidencias positivas como negativas
- No uses regex para todo: Para parsear HTML o XML, usa un parser dedicado. Para JSON, usa
JSON.parse(). Las regex no son adecuadas para lenguajes con anidamiento
Practica y perfecciona tus patrones con nuestra herramienta de prueba regex, que te muestra coincidencias en tiempo real y explica cada parte del patron.
Prueba esta herramienta:
Abrir herramienta→Preguntas frecuentes
Cual es la diferencia entre * + y ? en regex?
El asterisco (*) significa 0 o mas repeticiones del elemento anterior: 'ab*c' coincide con 'ac', 'abc', 'abbc'. El signo mas (+) significa 1 o mas repeticiones: 'ab+c' coincide con 'abc', 'abbc' pero NO con 'ac'. El signo de interrogacion (?) significa 0 o 1 repeticion (opcional): 'colou?r' coincide con 'color' y 'colour'.
Como valido un email con expresion regular?
Un patron practico es: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$. Este valida la estructura basica: parte local con caracteres permitidos, arroba, dominio y TLD de al menos 2 letras. Sin embargo, la especificacion completa de email (RFC 5322) es extremadamente compleja. Para produccion, complementa la validacion regex con verificacion del lado del servidor.
Que significa \d \w y \s en regex?
Son clases de caracteres predefinidas (shorthand). \d equivale a [0-9] (cualquier digito). \w equivale a [a-zA-Z0-9_] (cualquier caracter alfanumerico mas guion bajo). \s equivale a cualquier espacio en blanco (espacio, tabulacion, salto de linea). Sus versiones en mayuscula (\D, \W, \S) son la negacion: cualquier caracter que NO sea digito, palabra o espacio, respectivamente.
Que es un lookahead y para que sirve?
Un lookahead es una asercion que verifica si un patron existe despues de la posicion actual sin consumir caracteres. El lookahead positivo (?=patron) verifica que el patron SI existe. El negativo (?!patron) verifica que NO existe. Son utiles para validaciones complejas como contrasenas: ^(?=.*[A-Z])(?=.*\d).{8,}$ verifica que haya al menos una mayuscula y un digito sin importar su posicion.
Que es el backtracking catastrofico y como evitarlo?
El backtracking catastrofico ocurre cuando un patron ambiguo hace que el motor de regex pruebe una cantidad exponencial de combinaciones. Ejemplo: (a+)+$ con la entrada 'aaaaaaaaaaab'. El motor intenta todas las formas de dividir las 'a' entre los dos cuantificadores antes de fallar. Para evitarlo: se especifico en tus patrones, evita cuantificadores anidados como (a+)+, y usa cuantificadores posesivos (a++) o grupos atomicos cuando esten disponibles.
Las regex funcionan igual en todos los lenguajes de programacion?
No exactamente. Aunque la sintaxis basica es similar, cada lenguaje tiene su propio 'sabor' (flavor) de regex. JavaScript no soporta lookbehind de longitud variable. Python tiene el modulo re y el mas avanzado regex. Java requiere doble escape (\\d en vez de \d). PCRE (PHP, Perl) soporta recursion y condicionales. Las diferencias mas comunes estan en lookahead/lookbehind, Unicode, y funciones avanzadas como recursion.