Expresiones regulares en Python

El módulo re de Python tiene cuatro funciones para buscar que se parecen mucho. La diferencia entre ellas —y una letra, la r delante del patrón— explican la mayoría de los fallos.

La r delante

print("\d" == "\\d", r"\d" == "\\d")
salidaSyntaxWarning: "\d" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\d"? A raw string is also an option.

Python 3.14 avisa: en una cadena normal, la barra invertida tiene significado propio, y "\d" funciona hoy por casualidad. Escribe los patrones siempre con r"...", una cadena «cruda» donde la barra es solo una barra.

Las cuatro funciones

import re

print(re.findall(r"\d+", "11 es un número y 12 también"))
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", "pedido del 2026-10-08 enviado")
print(m.group(), m.group(1), m.span())
print(re.match(r"\d+", "pedido 42"), re.search(r"\d+", "pedido 42").group())
print(re.fullmatch(r"\d{5}", "28013") is not None, re.fullmatch(r"\d{5}", "28013x") is not None)
salida['11', '12']
2026-10-08 2026 (11, 21)
None 42
True False
FunciónBuscaDevuelve
findalltodas las coincidenciasuna lista
searchla primera, en cualquier sitioun objeto o None
matchsolo al principioun objeto o None
fullmatchla cadena enteraun objeto o None

La tercera línea es la trampa: re.match(r"\d+", "pedido 42") devuelve None porque la cadena no empieza por un número, aunque lo tenga. Para validar un dato completo —un código postal, un DNI—, fullmatch.

Grupos con nombre

m = re.search(r"(?P<año>\d{4})-(?P<mes>\d{2})", "2026-10")
print(m.group("año"), m["mes"], m.groupdict())
salida2026 10 {'año': '2026', 'mes': '10'}

Mejor que contar paréntesis. Y en Python el nombre puede llevar eñes y tildes, cosa que en Java, por ejemplo, no se permite.

Reemplazar y partir

print(re.sub(r"\s*,\s*", " | ", "uno, dos,tres"))
print(re.split(r"\d+", "a1b22c333d"))
salidauno | dos | tres
['a', 'b', 'c', 'd']

Los acentos, bien de serie

print(re.findall(r"\w+", "añil camión pingüino"))
print(re.findall(r"\w+", "añil camión", flags=re.ASCII))
salida['añil', 'camión', 'pingüino']
['a', 'il', 'cami', 'n']

En Python 3, \w entiende Unicode por omisión: las eñes y las tildes cuentan como letras. Solo con re.ASCII vuelve al comportamiento antiguo, y se ve lo que haría: partir las palabras por cada letra acentuada.

Validar un correo: con cuidado

patron = re.compile(r"^\w+@\w+\.\w+$")
for c in ("ana@correo.com", "ana.lopez@correo.com", "ana@correo.co.uk", "José@correo.es"):
    print(f"{c:<22}", bool(patron.match(c)))
salidaana@correo.com         True
ana.lopez@correo.com   False
ana@correo.co.uk       False
José@correo.es         True
Una regex de correo siempre se equivoca en algún caso. Esta rechaza dos direcciones normales —con un punto en el nombre, con un dominio de dos partes— y acepta una con tilde que muchos servidores no admiten. La de la versión anterior era más completa, pero tampoco es perfecta: la norma de las direcciones de correo es demasiado complicada para una expresión regular. Lo sensato es una comprobación básica —que haya una arroba y un punto después— y confirmar la dirección mandando un correo.

Cuando el patrón está mal

salidare.error: missing ), unterminated subpattern at position 0

Si el patrón no es una constante tuya, sino que viene de un archivo o de un usuario, compílalo dentro de un try y captura re.error.

Más información en inglés: Regular expressions in Python.

Todo el código se ejecutó con Python 3.14 en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.