Expresiones regulares
Expresiones regulares
Section titled “Expresiones regulares”Las expresiones regulares (regex o regexp) son patrones que describen conjuntos de cadenas de caracteres. Se utilizan para:
- 🔍 Búsqueda de patrones en texto
- ✓ Validación de datos (emails, teléfonos, etc.)
- 🔁 Sustitución de texto
- 🔎 Extracción de información específica
- 🧹 Procesamiento y limpieza de datos
Las expresiones regulares son fundamentales en programación porque permiten:
- Automatizar tareas de procesamiento de texto
- Validar formularios web
- Parsear logs y archivos
- Procesar grandes volúmenes de datos textuales
Conceptos Básicos
Section titled “Conceptos Básicos”Una expresión regular es una secuencia de caracteres que forma un patrón de búsqueda. Los caracteres pueden ser:
- Literales: Coinciden exactamente (
a,1,@) - Metacaracteres: Tienen significado especial (
. * + ? ^ $ [ ] { } ( ) | \)
Primera Expresión Regular
hello# COINCIDEecho "hello world" | grep -e "hello"
# NO COINCIDEecho "helo world" | grep -e "hello"Esta expresión busca exactamente la palabra “hello” en el texto.
Metacaracteres Fundamentales
Section titled “Metacaracteres Fundamentales”El Punto (.)
Section titled “El Punto (.)”Coincide con cualquier carácter excepto salto de línea.
h.llo# COINCIDEecho "hallo" | grep -e "h.llo"
# NO COINCIDEecho "hllo" | grep -e "h.llo"✓ Coincide: hello, hallo, hxllo
✗ No coincide: hllo, hllo
La Barra Invertida ()
Section titled “La Barra Invertida ()”Escapa metacaracteres para usarlos literalmente.
3\.14# COINCIDEecho "El valor es 3.14" | grep -e "3\.14"
# NO COINCIDEecho "El valor es 314" | grep -e "3\.14"✓ Coincide: 3.14
✗ No coincide: 3414
Cuantificadores
Section titled “Cuantificadores”Los cuantificadores especifican cuántas veces debe aparecer un elemento.
Cuantificadores Básicos
Section titled “Cuantificadores Básicos”| Cuantificador | Descripción | Ejemplo | Coincide |
|---|---|---|---|
* | 0 o más veces | ab*c | ac, abc, abbc |
+ | 1 o más veces | ab+c | abc, abbc |
? | 0 o 1 vez | ab?c | ac, abc |
{n} | Exactamente n veces | ab{3}c | abbbc |
{n,} | n o más veces | ab{2,}c | abbc, abbbc |
{n,m} | Entre n y m veces | ab{2,4}c | abbc, abbbc, abbbbc |
Ejemplo Práctico: Validar Números
Section titled “Ejemplo Práctico: Validar Números”\d{3}-\d{3}-\d{4}# COINCIDEecho "Mi teléfono es 123-456-7890" | grep -e "[0-9]\{3\}-[0-9]\{3\}-[0-9]\{4\}"
# NO COINCIDEecho "Mi teléfono es 12-3456-789" | grep -e "[0-9]\{3\}-[0-9]\{3\}-[0-9]\{4\}"✓ Coincide: 123-456-7890
Cuantificadores Greedy vs Lazy
Section titled “Cuantificadores Greedy vs Lazy”Cuantificadores Greedy (Ávidos)
Section titled “Cuantificadores Greedy (Ávidos)”Por defecto, intentan coincidir con la mayor cantidad de caracteres posible.
<.+># COINCIDEecho "<div>Hello</div>" | grep -e "<.*>"
# NO COINCIDEecho "sin etiquetas" | grep -e "<.*>"En <div>Hello</div>: coincide con <div>Hello</div> (toda la cadena)
Cuantificadores Lazy (Perezosos)
Section titled “Cuantificadores Lazy (Perezosos)”Añadiendo ?, intentan coincidir con la menor cantidad de caracteres posible.
<.+?># COINCIDE (usa PCRE para lazy)echo "<div>Hello</div>" | grep -P -o -e "<.+?>"
# NO COINCIDEecho "sin etiquetas" | grep -P -o -e "<.+?>"En <div>Hello</div>: coincide con <div> únicamente
| Greedy | Lazy | Descripción |
|---|---|---|
* | *? | 0 o más (mínimo) |
+ | +? | 1 o más (mínimo) |
? | ?? | 0 o 1 (prefiere 0) |
{n,m} | {n,m}? | Entre n y m (mínimo) |
Clases de Caracteres
Section titled “Clases de Caracteres”Clases Predefinidas
Section titled “Clases Predefinidas”| Clase | Descripción | Equivalente |
|---|---|---|
\\d | Dígito | [0-9] |
\\w | Carácter de palabra | [a-zA-Z0-9_] |
\\s | Espacio en blanco | [ \t\n\r\f] |
\\D | No dígito | [^0-9] |
\\W | No carácter de palabra | [^a-zA-Z0-9_] |
\\S | No espacio en blanco | [^ \t\n\r\f] |
Clases Personalizadas
Section titled “Clases Personalizadas”[aeiou] # Cualquier vocal[0-9] # Cualquier dígito[a-zA-Z] # Cualquier letra[^0-9] # Cualquier carácter que NO sea dígito# COINCIDE (vocales)echo "hola" | grep -e "[aeiou]"
# NO COINCIDE (vocales)echo "hll" | grep -e "[aeiou]"
# COINCIDE (dígitos)echo "2025" | grep -e "[0-9]"
# NO COINCIDE (dígitos)echo "abcd" | grep -e "[0-9]"Rangos de Caracteres
Section titled “Rangos de Caracteres”[a-z] # Letras minúsculas[A-Z] # Letras mayúsculas[0-9] # Dígitos[a-fA-F0-9] # Caracteres hexadecimales# COINCIDE (minúsculas)echo "abc" | grep -e "[a-z]"
# NO COINCIDE (minúsculas)echo "ABC" | grep -e "[a-z]"
# COINCIDE (hex)echo "F1" | grep -e "[a-fA-F0-9]"
# NO COINCIDE (hex)echo "G" | grep -e "[a-fA-F0-9]"Anclas y Límites
Section titled “Anclas y Límites”Anclas de Posición
Section titled “Anclas de Posición”| Ancla | Descripción | Ejemplo |
|---|---|---|
^ | Inicio de línea | ^Hello |
$ | Final de línea | mundo$ |
\\b | Límite de palabra | \\bcat\\b |
\\B | No límite de palabra | \\Bcat\\B |
Ejemplos de Anclas
Section titled “Ejemplos de Anclas”^[A-Z] # Línea que empieza con mayúscula\.$ # Línea que termina con punto\bpython\b # La palabra "python" completa# COINCIDE (empieza con mayúscula)echo "Hola mundo" | grep -e "^[A-Z]"
# NO COINCIDE (empieza con mayúscula)echo "hola mundo" | grep -e "^[A-Z]"
# COINCIDE (termina con punto)echo "Esto es una frase." | grep -e "\.$"
# NO COINCIDE (termina con punto)echo "Esto no tiene punto" | grep -e "\.$"
# COINCIDE (palabra completa usando -w)echo "me gusta python y más" | grep -w -e "python"
# NO COINCIDE (palabra completa usando -w)echo "pythonic" | grep -w -e "python"Grupos y Capturas
Section titled “Grupos y Capturas”Grupos de Captura
Section titled “Grupos de Captura”Los paréntesis () crean grupos que capturan el texto coincidente.
(\d{4})-(\d{2})-(\d{2})# COINCIDEecho "Fecha: 2023-12-25" | grep -e "[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}"
# NO COINCIDEecho "Fecha: 23-12-25" | grep -e "[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}"En 2023-12-25:
- Grupo 1:
2023 - Grupo 2:
12 - Grupo 3:
25
Grupos Sin Captura
Section titled “Grupos Sin Captura”(?:...) agrupa sin capturar el contenido.
(?:https?|ftp)://\S+…
# COINCIDE (usa PCRE para grupos no capturantes y \S)echo "Visita http://ejemplo.com/pagina" | grep -P -o -e "(?:https?|ftp)://\S+"
# NO COINCIDEecho "texto sin url" | grep -P -o -e "(?:https?|ftp)://\S+"Grupos Nombrados
Section titled “Grupos Nombrados”Permiten asignar nombres a los grupos.
(?P<año>\d{4})-(?P<mes>\d{2})-(?P<día>\d{2})# COINCIDE (grupos nombrados con PCRE)echo "2023-12-25" | grep -P -e "(?P<año>\d{4})-(?P<mes>\d{2})-(?P<día>\d{2})"
# NO COINCIDEecho "23-12-25" | grep -P -e "(?P<año>\d{4})-(?P<mes>\d{2})-(?P<día>\d{2})"Conceptos Avanzados
Section titled “Conceptos Avanzados”Lookahead (Búsqueda hacia adelante)
Section titled “Lookahead (Búsqueda hacia adelante)”| Tipo | Sintaxis | Descripción |
|---|---|---|
| Positivo | (?=...) | Debe seguir el patrón |
| Negativo | (?!...) | NO debe seguir el patrón |
Ejemplos de Lookahead
Section titled “Ejemplos de Lookahead”# Contraseña que debe tener al menos un dígito^(?=.*\d).{8,}$
# Palabra seguida de vocal\w+(?=[aeiou])# COINCIDE (lookahead, requiere PCRE)echo "Abcdef1g" | grep -P -e "^(?=.*\d).{8,}$"
# NO COINCIDE (lookahead, requiere PCRE)echo "Abcdefgh" | grep -P -e "^(?=.*\d).{8,}$"
# COINCIDE (palabra seguida de vocal, extracción con -o)echo "textoe" | grep -P -o -e "\\w+(?=[aeiou])"
# NO COINCIDEecho "txtb" | grep -P -o -e "\\w+(?=[aeiou])"Lookbehind (Búsqueda hacia atrás)
Section titled “Lookbehind (Búsqueda hacia atrás)”| Tipo | Sintaxis | Descripción |
|---|---|---|
| Positivo | (?<=...) | Debe preceder el patrón |
| Negativo | (?<!...) | NO debe preceder el patrón |
Ejemplos de Lookbehind
Section titled “Ejemplos de Lookbehind”# Número precedido por símbolo $(?<=\$)\d+
# Palabra NO precedida por "no "(?<!no )\w+# COINCIDE (lookbehind, requiere PCRE)echo "$100" | grep -P -o -e "(?<=\$)\d+"
# NO COINCIDE (lookbehind, requiere PCRE)echo "100" | grep -P -o -e "(?<=\$)\d+"
# COINCIDE (palabra no precedida por "no ")echo "esto no es" | grep -P -o -e "(?<!no )\w+" # ejemplo simple
# NO COINCIDEecho "no permitir" | grep -P -o -e "(?<!no )\w+"Alternación (|)
Section titled “Alternación (|)”Permite elegir entre múltiples patrones.
(gato|perro|pez)COINCIDE -> echo “Tengo un perro” | grep -e “(gato|perro|pez)” -e “gato|perro|pez” NO COINCIDE -> echo “Tengo un hamster” | grep -e “gato|perro|pez”
Coincide con gato, perro o pez.
Implementación en Diferentes Lenguajes
Section titled “Implementación en Diferentes Lenguajes”Python
Section titled “Python”import re
# Compilar expresión regularpattern = re.compile(r'\d{3}-\d{3}-\d{4}')
# Buscar coincidenciastext = "Mi teléfono es 123-456-7890"match = pattern.search(text)
if match: print(f"Encontrado: {match.group()}")
# Encontrar todas las coincidenciasmatches = pattern.findall(text)
# Sustituir textonuevo_texto = pattern.sub("XXX-XXX-XXXX", text)
# Grupos de capturafecha_pattern = r'(\d{4})-(\d{2})-(\d{2})'match = re.search(fecha_pattern, "2023-12-25")if match: año, mes, día = match.groups() print(f"Año: {año}, Mes: {mes}, Día: {día}")JavaScript
Section titled “JavaScript”// Crear expresión regularconst pattern = /\d{3}-\d{3}-\d{4}/g;
// Buscar en textoconst text = "Mi teléfono es 123-456-7890";const match = text.match(pattern);
// Test de coincidenciaif (pattern.test(text)) { console.log("Patrón encontrado");}
// Sustituir textoconst newText = text.replace(pattern, "XXX-XXX-XXXX");
// Grupos de capturaconst datePattern = /(\d{4})-(\d{2})-(\d{2})/;const dateMatch = "2023-12-25".match(datePattern);if (dateMatch) { const [full, year, month, day] = dateMatch; console.log(`Año: ${year}, Mes: ${month}, Día: ${day}`);}
// Usar exec() para múltiples coincidenciasconst globalPattern = /\d+/g;let result;while ((result = globalPattern.exec("123 456 789")) !== null) { console.log(`Encontrado: ${result[0]} en posición ${result.index}`);}import java.util.regex.Pattern;import java.util.regex.Matcher;
public class RegexExample { public static void main(String[] args) { // Compilar patrón Pattern pattern = Pattern.compile("\\d{3}-\\d{3}-\\d{4}");
String text = "Mi teléfono es 123-456-7890"; Matcher matcher = pattern.matcher(text);
// Buscar coincidencia if (matcher.find()) { System.out.println("Encontrado: " + matcher.group()); }
// Reemplazar texto String newText = matcher.replaceAll("XXX-XXX-XXXX");
// Grupos de captura Pattern datePattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})"); Matcher dateMatcher = datePattern.matcher("2023-12-25");
if (dateMatcher.find()) { String year = dateMatcher.group(1); String month = dateMatcher.group(2); String day = dateMatcher.group(3); System.out.println("Año: " + year + ", Mes: " + month + ", Día: " + day); } }}<?php// Buscar coincidencias$pattern = '/\d{3}-\d{3}-\d{4}/';$text = 'Mi teléfono es 123-456-7890';
if (preg_match($pattern, $text, $matches)) { echo "Encontrado: " . $matches[0] . "\n";}
// Encontrar todas las coincidenciaspreg_match_all('/\d+/', 'Los números son 123, 456 y 789', $allMatches);print_r($allMatches[0]);
// Sustituir texto$newText = preg_replace($pattern, 'XXX-XXX-XXXX', $text);
// Grupos de captura con nombres$datePattern = '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/';if (preg_match($datePattern, '2023-12-25', $matches)) { echo "Año: " . $matches['year'] . "\n"; echo "Mes: " . $matches['month'] . "\n"; echo "Día: " . $matches['day'] . "\n";}
// Validar emailfunction validarEmail($email) { $pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/'; return preg_match($pattern, $email);}?>#!/bin/bash
# Usando grep con regextext="Mi teléfono es 123-456-7890"echo "$text" | grep -E '\\d{3}-\\d{3}-\\d{4}'
# Usando sed para sustituirecho "$text" | sed 's/[0-9]\{3\}-[0-9]\{3\}-[0-9]\{4\}/XXX-XXX-XXXX/'
# Validación con condicionalesemail="usuario@ejemplo.com"if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then echo "Email válido"else echo "Email inválido"fi
# Extraer información de un archivo# Buscar direcciones IP en un archivo de loggrep -oE '\\b([0-9]{1,3}\\.){3}[0-9]{1,3}\\b' /var/log/access.log
# Extraer dominios de URLsecho "https://www.ejemplo.com/pagina" | grep -oE 'https?://([^/]+)'
# Capturar grupos con grep# Extraer fecha del formato DD-MM-YYYYecho "Fecha: 25-12-2023" | grep -oE '[0-9]{2}-[0-9]{2}-[0-9]{4}'Ejemplos Prácticos
Section titled “Ejemplos Prácticos”1. Validación de Email
Section titled “1. Validación de Email”^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$Explicación:
^- Inicio de cadena[a-zA-Z0-9._%+-]+- Uno o más caracteres válidos para el usuario@- Símbolo arroba literal[a-zA-Z0-9.-]+- Uno o más caracteres válidos para el dominio\.- Punto literal[a-zA-Z]{2,}- Al menos 2 letras para la extensión$- Final de cadena
2. Validación de Contraseña Fuerte
Section titled “2. Validación de Contraseña Fuerte”^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$Explicación:
(?=.*[a-z])- Al menos una minúscula(?=.*[A-Z])- Al menos una mayúscula(?=.*\d)- Al menos un dígito(?=.*[@$!%*?&])- Al menos un carácter especial[A-Za-z\d@$!%*?&]{8,}- Mínimo 8 caracteres de los tipos permitidos
3. Extracción de URLs
Section titled “3. Extracción de URLs”https?://(?:[-\w.])+(?:[:\d]+)?(?:/(?:[\w/_.])*)?(?:\?(?:[\w&=%.])*)?(?:#(?:[\w.])*)?4. Validación de Teléfono Internacional
Section titled “4. Validación de Teléfono Internacional”^\+?[1-9]\d{1,14}$5. Extracción de Hashtags
Section titled “5. Extracción de Hashtags”#[a-zA-Z0-9_]+6. Validación de Fecha (DD/MM/YYYY)
Section titled “6. Validación de Fecha (DD/MM/YYYY)”^(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[0-2])/([0-9]{4})$7. Extracción de Direcciones IP
Section titled “7. Extracción de Direcciones IP”\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b8. Validación de Código Postal Español
Section titled “8. Validación de Código Postal Español”^[0-4][0-9]{4}$|^5[0-2][0-9]{3}$Ejercicios y Casos de Uso
Section titled “Ejercicios y Casos de Uso”Ejercicio 1: Validar DNI Español
Section titled “Ejercicio 1: Validar DNI Español”Crear una expresión regular que valide un DNI español (8 dígitos + 1 letra).
Solución
^[0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKE]$Ejercicio 2: Extraer Menciones de Twitter
Section titled “Ejercicio 2: Extraer Menciones de Twitter”Extraer todas las menciones (@usuario) de un texto.
Solución
@[a-zA-Z0-9_]+Ejercicio 3: Validar Tarjeta de Crédito
Section titled “Ejercicio 3: Validar Tarjeta de Crédito”Validar números de tarjeta de crédito (16 dígitos, pueden estar separados por espacios o guiones).
Solución
^[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}[\s\-]?[0-9]{4}$Ejercicio 4: Limpiar Espacios Extra
Section titled “Ejercicio 4: Limpiar Espacios Extra”Reemplazar múltiples espacios con un solo espacio.
Solución
\s+Reemplazar con: (un espacio)
Casos de Uso Reales
Section titled “Casos de Uso Reales”1. Procesamiento de Logs
Section titled “1. Procesamiento de Logs”# Extraer IPs y códigos de estado de logs de Apachegrep -oE '\\b([0-9]{1,3}\\.){3}[0-9]{1,3}\\b.*" [0-9]{3} ' access.log2. Limpieza de Datos
Section titled “2. Limpieza de Datos”# Limpiar números de teléfonoimport rephone = "+1 (555) 123-4567"clean_phone = re.sub(r'[^\d+]', '', phone)3. Validación de Formularios Web
Section titled “3. Validación de Formularios Web”// Validar formulario de registrofunction validarFormulario(email, password) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
return emailRegex.test(email) && passwordRegex.test(password);}Consejos y Mejores Prácticas
Section titled “Consejos y Mejores Prácticas”✓ Buenas Prácticas
Section titled “✓ Buenas Prácticas”- Usa raw strings en Python:
r"patron" - Compila patrones que uses repetidamente
- Usa grupos no capturadores
(?:...)cuando no necesites el contenido - Escapa metacaracteres cuando los uses literalmente
- Documenta regex complejas con comentarios
- Usa herramientas online para probar patrones
✗ Errores Comunes
Section titled “✗ Errores Comunes”- No escapar metacaracteres especiales
- Usar cuantificadores greedy cuando necesitas lazy
- No anclar patrones cuando es necesario
- Regex demasiado complejas - divídelas en partes
- No considerar casos edge como cadenas vacías
⚙️ Optimización
Section titled “⚙️ Optimización”- Evita backtracking excesivo
- Usa clases de caracteres en lugar de alternación cuando sea posible
- Ancla patrones al inicio
^cuando sepas que debe empezar ahí - Usa quantificadores posesivos cuando no necesites backtracking
Recursos y Herramientas
Section titled “Recursos y Herramientas”🌐 Herramientas Online
Section titled “🌐 Herramientas Online”📚 Referencias
Section titled “📚 Referencias”🧩 Extensiones de Editor
Section titled “🧩 Extensiones de Editor”- VS Code: Regex Previewer, Regex Explain
- Sublime Text: RegReplace
- Vim: Regex plugins
Tabla de Referencia Rápida
Section titled “Tabla de Referencia Rápida”| Elemento | Descripción | Ejemplo |
|---|---|---|
. | Cualquier carácter | a.c → abc, axc |
* | 0 o más | ab*c → ac, abc |
+ | 1 o más | ab+c → abc, abbc |
? | 0 o 1 | ab?c → ac, abc |
^ | Inicio | ^abc → inicio con abc |
$ | Final | abc$ → termina con abc |
[] | Clase de caracteres | [abc] → a, b, o c |
() | Grupo | (abc)+ → abc, abcabc |
| | Alternación | a|b → a o b |
\\d | Dígito | \\d+ → uno o más dígitos |
\\w | Carácter de palabra | \\w+ → una o más letras |
\\s | Espacio | \\s+ → uno o más espacios |
Conclusión
Section titled “Conclusión”Las expresiones regulares son una herramienta poderosa para el procesamiento de texto. Aunque pueden parecer intimidantes al principio, con práctica se vuelven intuitivas y extremadamente útiles.
Próximos Pasos:
Section titled “Próximos Pasos:”- Practica con ejercicios simples
- Experimenta con herramientas online
- Aplica regex en tus proyectos
- Estudia casos de uso específicos de tu área
¡Recuerda: la maestría en regex viene con la práctica constante! 🎯