Publicado en

Expresiones regulares para developers: referencia

Patrones de expresiones regulares para email, URL, fecha y números sobre fondo oscuro

Referencia de expresiones regulares para uso cotidiano en código, terminal y editores. Los patrones que realmente se usan, sin teoría innecesaria.

Sintaxis básica

# Caracteres especiales
.       cualquier carácter (excepto salto de línea)
\d      dígito (0-9)          \D  no dígito
\w      letra, dígito o _     \W  lo contrario
\s      espacio, tab, newline  \S  no espacio
\b      límite de palabra      \B  no límite

# Anclas
^       inicio de línea / cadena
$       fin de línea / cadena
\A      inicio de la cadena (solo)
\Z      fin de la cadena (solo)

# Clases de caracteres
[abc]        a, b o c
[a-z]        cualquier letra minúscula
[A-Za-z0-9]  alfanumérico
[^abc]        cualquier carácter EXCEPTO a, b o c

# Cuantificadores
*       0 o más
+       1 o más
?       0 o 1 (hace opcional el anterior)
{3}     exactamente 3
{3,}    3 o más
{3,6}   entre 3 y 6
*? +? ?? {3,6}?  versiones no codiciosas (lazy)

Grupos y alternativas

(abc)      grupo de captura
(?:abc)    grupo sin captura (más eficiente)
(?Pabc)  grupo con nombre (Python)  /(?abc)/  (JS/PCRE)
a|b        a o b
\1         referencia al grupo 1 capturado

# Lookahead y lookbehind
(?=texto)    lookahead positivo (seguido de "texto")
(?!texto)    lookahead negativo (no seguido de "texto")
(?<=texto)   lookbehind positivo (precedido de "texto")
(?<!texto)   lookbehind negativo (no precedido de "texto")

Patrones esenciales

# Email (simplificado, válido para la mayoría de casos)
[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}

# URL
https?://[^\s/$.?#].[^\s]*

# IPv4
\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b

# Fecha YYYY-MM-DD
\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])

# Fecha DD/MM/YYYY
(0[1-9]|[12]\d|3[01])\/(0[1-9]|1[0-2])\/\d{4}

# Hora HH:MM o HH:MM:SS
([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?

# Número entero (positivo o negativo)
-?\d+

# Número decimal
-?\d+(\.\d+)?

# Solo dígitos
^\d+$

# Solo letras (cualquier caso)
^[a-zA-Z]+$

# Alfanumérico
^[a-zA-Z0-9]+$

# Código postal España (5 dígitos)
\b\d{5}\b

# Teléfono España (formatos habituales)
(\+34|0034)?[ \-]?[6789]\d{8}

# DNI España
\d{8}[A-HJ-NP-TV-Z]

# Tarjeta de crédito (16 dígitos con o sin espacios/guiones)
\d{4}[\s\-]?\d{4}[\s\-]?\d{4}[\s\-]?\d{4}

# Hash MD5
[a-f0-9]{32}

# Hash SHA1
[a-f0-9]{40}

# UUID
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}

Uso en terminal: grep y sed

# grep: buscar
grep -E "patron"  archivo    # ERE (regex extendida)
grep -P "patron"  archivo    # PCRE (Perl, más completa, no siempre disponible)
grep -Eo "patron" archivo    # solo mostrar la parte que coincide

# Ejemplos reales
grep -E "^\s*(ERROR|WARN)" app.log        # líneas que empiezan con ERROR o WARN
grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log  # IPs
grep -Eo '"status":\s*[0-9]+' api.log     # extraer códigos de estado de JSON

# sed: reemplazar
sed 's/patron/reemplazo/'  archivo        # primera ocurrencia por línea
sed 's/patron/reemplazo/g' archivo        # todas las ocurrencias
sed -E 's/patron/reemplazo/g' archivo     # con regex extendida
sed -i 's/localhost/prod.db.com/g' config.env   # reemplazar en el archivo

# Ejemplos reales
sed -E 's/(\d{4})-(\d{2})-(\d{2})/\3\/\2\/\1/g' fechas.txt  # YYYY-MM-DD → DD/MM/YYYY
sed '/^#/d' config.txt     # eliminar líneas de comentario
sed '/^\s*$/d' archivo.txt # eliminar líneas vacías

Uso en código

// JavaScript
const emailRegex = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/;
const esEmail = emailRegex.test(input);

// Extraer todos los matches
const ips = texto.match(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g) ?? [];

// Reemplazar
const limpio = texto.replace(/\s+/g, ' ').trim();

// Grupos con nombre
const { year, month, day } = '2024-06-13'.match(
  /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
).groups;
# Python
import re

patron = re.compile(r'^[\w.%+\-]+@[\w.\-]+\.[a-zA-Z]{2,}$')
es_email = bool(patron.match(email))

# Encontrar todos los matches
ips = re.findall(r'\b\d{1,3}(?:\.\d{1,3}){3}\b', texto)

# Grupos con nombre
m = re.match(r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})', fecha)
if m:
    print(m.group('year'), m.group('month'))

# Reemplazar con función
resultado = re.sub(r'\d+', lambda m: str(int(m.group())*2), texto)

Modificadores / flags

i   insensible a mayúsculas        /patron/i    re.IGNORECASE
m   multilínea (^ y $ por línea)  /patron/m    re.MULTILINE
s   . coincide con newline        /patron/s    re.DOTALL
g   global (todos los matches)    /patron/g    (no aplica en Python)
x   extendida (ignora espacios y permite comentarios)   re.VERBOSE