Regex en Python: guía de expresiones regulares

Actualizado el: 11/07/2026
Tempo de leitura: 5 minutos
Uso de expressões regulares regex para manipulação de texto em Python

Las expresiones regulares describen patrones de texto. Pueden localizar fechas en un documento, extraer identificadores de registros, normalizar espacios, validar formatos sencillos o dividir entradas que utilizan varios separadores. Python ofrece esta funcionalidad mediante el módulo estándar re.

En esta guía de regex en Python aprenderás cadenas raw, clases de caracteres, anclas, cuantificadores, grupos, alternancia, search(), fullmatch(), findall(), finditer(), sub(), split(), flags, patrones compilados y reglas de seguridad.

Las expresiones regulares son potentes, pero no siempre son la mejor solución. Los métodos de cadenas en Python resultan más claros para reemplazos literales, prefijos fijos y divisiones sencillas. Los formatos estructurados como JSON o HTML deben procesarse con parsers específicos.

Importar el módulo re

import re

No necesitas instalar paquetes. Consulta la documentación oficial de re y el HOWTO de expresiones regulares.

Utilizar cadenas raw

Las expresiones regulares y las cadenas de Python utilizan barras invertidas. El prefijo r evita que Python procese la mayoría de los escapes antes de enviar el patrón al motor regex.

patron = r"\d{4}-\d{2}-\d{2}"

Las cadenas raw facilitan la lectura. Aun así, no pueden terminar con una única barra invertida.

Caracteres literales y metacaracteres

  • .: cualquier carácter excepto salto de línea, normalmente.
  • ^: inicio de cadena o línea.
  • $: final de cadena o línea.
  • *: cero o más repeticiones.
  • +: una o más repeticiones.
  • ?: cero o una repetición, o modificador no codicioso.
  • {m,n}: entre m y n repeticiones.
  • [...]: clase de caracteres.
  • (...): grupo.
  • |: alternancia.

Escapa un metacarácter para buscarlo literalmente:

patron_precio = r"\$\d+\.\d{2}"

Cuando insertes texto externo dentro de un patrón, usa re.escape(texto).

Clases de caracteres

r"[abc]"       # a, b o c
r"[a-z]"       # letra minúscula ASCII del rango
r"[^0-9]"      # carácter que no es un dígito ASCII
r"\d"          # dígito Unicode por defecto
r"\w"          # alfanumérico o guion bajo
r"\s"          # espacio en blanco
r"\D"          # no es un dígito
r"\W"          # no es carácter de palabra
r"\S"          # no es espacio

\d puede coincidir con dígitos Unicode. Utiliza [0-9] o el flag ASCII cuando el formato exija solamente esos caracteres.

Buscar la primera coincidencia

re.search() recorre el texto y devuelve el primer objeto Match o None.

import re

texto = "El pedido 4832 está listo"
coincidencia = re.search(r"\d+", texto)

if coincidencia:
    print(coincidencia.group())
    print(coincidencia.start())
    print(coincidencia.span())

Comprueba siempre que exista una coincidencia antes de llamar a group(). La guía sobre None en Python explica cómo distinguir la ausencia de una coincidencia de otros valores falsos.

match(), search() y fullmatch()

  • match() comprueba solamente al inicio.
  • search() busca en cualquier posición.
  • fullmatch() exige que toda la cadena cumpla el patrón.
patron = r"[A-Z]{3}-[0-9]{4}"

print(re.match(patron, "ABC-1234 extra"))
print(re.search(patron, "Matrícula: ABC-1234"))
print(re.fullmatch(patron, "ABC-1234"))

Para validar el formato completo de un valor, fullmatch() expresa mejor la intención.

Encontrar todas las coincidencias

texto = "Tickets: AB-104, XY-220, CD-981"
codigos = re.findall(r"[A-Z]{2}-[0-9]{3}", texto)
print(codigos)

finditer() devuelve objetos Match de forma perezosa:

for coincidencia in re.finditer(r"[A-Z]{2}-[0-9]{3}", texto):
    print(coincidencia.group(), coincidencia.span())

Cuando también necesitas la posición de cada coincidencia, puedes combinar este patrón con enumerate() en Python para numerar resultados, líneas o registros.

Cuantificadores

r"a*"          # cero o más
r"a+"          # una o más
r"a?"          # cero o una
r"a{3}"        # exactamente tres
r"a{2,}"       # al menos dos
r"a{2,5}"      # entre dos y cinco

Los cuantificadores afectan al token anterior. Agrupa una secuencia cuando debas repetirla completa:

r"(?:ab){2,4}"

(?:...) es un grupo no capturante.

Coincidencia codiciosa y no codiciosa

texto = "<b>uno</b> y <b>dos</b>"

print(re.findall(r"<b>.*</b>", texto))
print(re.findall(r"<b>.*?</b>", texto))

El segundo patrón usa *? para consumir la menor cantidad posible. El ejemplo sirve para comprender el comportamiento, pero HTML real debe procesarse con un parser.

Grupos de captura

patron_fecha = r"([0-9]{4})-([0-9]{2})-([0-9]{2})"
coincidencia = re.fullmatch(patron_fecha, "2026-07-11")

if coincidencia:
    ano, mes, dia = coincidencia.groups()
    print(ano, mes, dia)

El patrón valida la forma, no si la fecha existe. Para reglas de calendario utiliza la guía de datetime en Python.

Grupos con nombre

patron = re.compile(
    r"(?P<ano>[0-9]{4})-"
    r"(?P<mes>[0-9]{2})-"
    r"(?P<dia>[0-9]{2})"
)

coincidencia = patron.fullmatch("2026-07-11")

if coincidencia:
    print(coincidencia.group("ano"))
    print(coincidencia.groupdict())

Los nombres facilitan la lectura de patrones complejos.

Alternancia

patron = r"gato|perro|pajaro"
print(re.findall(patron, "perro, gato y pajaro"))

Agrupa la alternancia cuando forme parte de otro patrón:

patron_archivo = r"informe\.(?:csv|json|xlsx)"

Reemplazar con sub()

texto = "Demasiados     espacios"
limpio = re.sub(r"\s+", " ", texto).strip()
print(limpio)

La sustitución también puede ser una función:

def ocultar_digitos(coincidencia):
    return "*" * len(coincidencia.group())


oculto = re.sub(r"[0-9]+", ocultar_digitos, "Tarjeta terminada en 1234")
print(oculto)

Para texto fijo, str.replace() suele ser más simple.

Dividir con un patrón

texto = "rojo, verde;azul | amarillo"
partes = re.split(r"\s*[,;|]\s*", texto)
print(partes)

Para datos tabulares completos, conviene utilizar el módulo dedicado que se explica en la guía de archivos CSV con Python en lugar de intentar interpretar todas las columnas con una única expresión regular.

Compilar patrones reutilizados

patron_ticket = re.compile(r"[A-Z]{2}-[0-9]{3}")

for texto in ["AB-123", "invalido", "XY-999"]:
    if patron_ticket.fullmatch(texto):
        print("Válido:", texto)

La compilación mejora la reutilización y hace explícita la configuración del patrón.

Flags de expresiones regulares

patron = re.compile(
    r"^error:.*$",
    flags=re.IGNORECASE | re.MULTILINE,
)

texto = "Info: inicio\nERROR: conexión fallida\nInfo: fin"
print(patron.findall(texto))
  • re.IGNORECASE: ignora mayúsculas y minúsculas.
  • re.MULTILINE: aplica ^ y $ a cada línea.
  • re.DOTALL: permite que el punto coincida con saltos.
  • re.VERBOSE: permite espacios y comentarios.
  • re.ASCII: limita ciertas clases abreviadas a ASCII.

Patrones legibles con VERBOSE

patron_correo = re.compile(
    r"""
    [A-Z0-9._%+-]+     # parte local
    @
    [A-Z0-9.-]+        # dominio
    \.
    [A-Z]{2,}           # etiqueta final
    """,
    re.IGNORECASE | re.VERBOSE,
)

Este ejemplo valida un formato común, no todos los correos posibles ni la existencia del buzón.

Proyecto práctico: analizar un log

Este proyecto combina expresiones regulares con Counter en Python, rutas gestionadas con pathlib y numeración de líneas mediante enumerate().

import re
from collections import Counter
from pathlib import Path

PATRON_LOG = re.compile(
    r"^(?P<fecha>[0-9]{4}-[0-9]{2}-[0-9]{2}T"
    r"[0-9]{2}:[0-9]{2}:[0-9]{2})\s+"
    r"(?P<nivel>DEBUG|INFO|WARNING|ERROR|CRITICAL)\s+"
    r"(?P<mensaje>.+)$"
)


def analizar_linea(linea):
    coincidencia = PATRON_LOG.fullmatch(linea.strip())
    return coincidencia.groupdict() if coincidencia else None


def analizar_archivo(ruta):
    registros = []
    lineas_invalidas = []
    niveles = Counter()

    with Path(ruta).open("r", encoding="utf-8", errors="replace") as archivo:
        for numero, linea in enumerate(archivo, start=1):
            registro = analizar_linea(linea)

            if registro is None:
                lineas_invalidas.append(numero)
                continue

            registros.append(registro)
            niveles[registro["nivel"]] += 1

    return registros, niveles, lineas_invalidas

En una aplicación real, los resultados y errores también pueden registrarse con el módulo logging de Python en lugar de depender únicamente de mensajes impresos.

Rendimiento y seguridad

Algunos patrones ambiguos pueden provocar retroceso excesivo con entradas especialmente construidas.

  • Prefiere clases específicas a puntos repetidos.
  • Evita cuantificadores anidados ambiguos.
  • Limita la longitud de entradas no confiables.
  • Prueba casos que deben fallar.
  • Utiliza un parser cuando el contenido tenga una gramática real.
  • Divide un problema complejo en varias validaciones simples.

Crea pruebas para coincidencias válidas, entradas rechazadas y casos límite. La guía de Pytest para principiantes muestra cómo organizar estas comprobaciones como pruebas de regresión.

Cuándo no utilizar regex

  • startswith() para prefijos fijos.
  • El operador in de Python para buscar una subcadena sencilla.
  • str.replace() para reemplazos literales.
  • split() para un separador fijo.
  • json para JSON.
  • Un parser HTML o XML para marcado.
  • datetime.strptime() para validar fechas reales.

Errores frecuentes

  • Olvidar el prefijo raw.
  • Llamar a group() sin comprobar None.
  • Usar match() cuando se necesita fullmatch().
  • Agregar grupos capturantes y sorprenderse con el resultado de findall().
  • Suponer que \d significa solamente dígitos ASCII.
  • Intentar analizar HTML arbitrario con regex.
  • Escribir una expresión enorme donde varias comprobaciones serían más claras.

Conclusión

Regex en Python es útil cuando el problema depende realmente de patrones de texto. Utiliza cadenas raw, elige conscientemente entre search() y fullmatch(), emplea grupos con nombre para extracciones estructuradas y prueba entradas válidas e inválidas.

Mantén los patrones pequeños, documenta los complejos con modo verbose y cambia a un parser especializado cuando los datos tengan un formato definido.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Logo do Python com o texto 'Python argparse CLI' abaixo
    Automatización y Scripts
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear una CLI en Python con argparse

    Crea una CLI en Python con argparse: argumentos, banderas, tipos, choices, subcomandos, validación, pruebas y empaquetado moderno.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Jogo da forca para iniciantes desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un juego del ahorcado en Python

    Crea un juego del ahorcado en Python con palabras aleatorias, validación, letras repetidas, vidas, dibujos ASCII, pistas y opción de

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Uso da função enumerate em loops Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    enumerate() en Python: bucles con índices

    Aprende enumerate() en Python para recorrer valores con índices, elegir el inicio, combinarlo con zip, procesar archivos y evitar contadores

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Quiz interativo no terminal desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un quiz en Python para la terminal

    Crea un quiz en Python para la terminal con preguntas, validación, puntuación, respuestas mezcladas, repetición, JSON y pruebas.

    Ler mais

    Tempo de leitura: 2 minutos
    11/07/2026
    Barra de progresso com tqdm para scripts Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    tqdm en Python: barras de progreso para scripts

    Añade barras de progreso a tus scripts con tqdm en Python: bucles, archivos, pandas, descargas, actualización manual y opciones útiles.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026
    Jogo de adivinhação de números desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Juego de adivinar números en Python

    Crea un juego de adivinar números en Python con niveles, pistas, intentos limitados, validación, repetición y funciones fáciles de probar.

    Ler mais

    Tempo de leitura: 3 minutos
    11/07/2026