Regex: busca, valida y extrae texto en Python

Actualizado el: 20/08/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

    Código de error sobre datos binarios que representa fallos manejados con urllib.error en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    urllib.error en Python: maneja errores HTTP

    Aprende urllib.error en Python para manejar URLError, HTTPError, descargas incompletas, retries selectivos y diagnósticos de red claros.

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026
    Teclas con la palabra HTML que representan entidades HTML en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    html.entities: convierte entidades HTML

    Aprende html.entities en Python para consultar entidades HTML, convertir nombres y code points y no confundir decodificación con sanitización.

    Ler mais

    Tempo de leitura: 7 minutos
    21/08/2026
    Carpeta con archivos que representa tipos MIME identificados con mimetypes en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    mimetypes: detecta tipos MIME de archivos

    Aprende mimetypes en Python para identificar tipos de archivo, validar cargas y definir Content-Type con más seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    20/08/2026
    Código HTML en una pantalla que representa análisis con html.parser en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    html.parser en Python: analiza HTML

    Aprende html.parser en Python para extraer texto, enlaces y metadatos, procesar HTML por bloques y no confundir parsing con sanitización.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026
    Persona usando un portátil en una sesión web que representa cookies con http.cookiejar en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    http.cookiejar en Python: gestiona cookies

    Aprende http.cookiejar en Python para mantener sesiones, aplicar políticas, persistir cookies de forma segura e integrar urllib.request.

    Ler mais

    Tempo de leitura: 5 minutos
    20/08/2026
    Rack de servidores que representa conexiones HTTP de bajo nivel con http.client en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    http.client en Python: HTTP de bajo nivel

    Aprende http.client en Python para controlar conexiones HTTP y HTTPS, streaming, headers, TLS, reutilización, límites y errores.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026