Saltar al contenido

# regex-con-python-desde-cero

Regex con Python desde Cero

Volver a la portada del curso
Notebook

Desafío de Programación con Regex

Sección 4 · Aplicaciones Prácticas

Desafío de Programación con Regex

El notebook desafios-regex reúne diez problemas tomados de la bandeja de soporte y del log del servidor de PyShop, ordenados de menor a mayor dificultad. Cada desafío trae un enunciado, una función vacía para completar y una celda de pruebas con assert. Mientras la función no esté resuelta, la prueba imprime «pendiente» en lugar de detener el notebook, así que puedes avanzar en cualquier orden. Las soluciones están al final, en una sección separada: resuelve primero y compara después.

Cómo trabajar

  1. Ejecuta la primera celda de código: define generar_tickets, generar_log y MESES, y la función probar que corre las pruebas de cada desafío.
  2. Lee el enunciado y escribe el patrón en la función. Prueba primero con los ejemplos cortos del enunciado.
  3. Ejecuta la celda de pruebas. Si sale «pendiente», imprime la coincidencia y su span() antes de cambiar el patrón.
  4. Cuando un desafío pase, ejecuta la línea que lo aplica a la bandeja completa y compara la cifra con la esperada.

La herramienta regex101, con el modo Python seleccionado, sirve para ver paso a paso qué coincide; el resultado que cuenta es el del notebook.

Los diez desafíos

#DesafíoHerramientasCifra esperada en la bandeja o el log
1Pedidos: normalizar ps-12345 y PS 67890 a PS-dddddclase, ?, (?i), grupo600 pedidos, 597 distintos
2Fechas: llevar los tres formatos a ISOfullmatch, grupos, MESES488 fechas, 0 sin convertir
3Teléfonos: dejar solo 10 dígitospartes opcionales, {4}369 teléfonos
4Montos: texto a floatsub, alternancia488 montos, suma 1,211,689.39
5Palabras repetidas: «favor favor» a «favor»retrorreferencia \1, \b21 tickets corregidos
6Rutas del log: /api/pedidos/243 a /api/pedidos/{id}lookahead, sub404 más frecuente: /productos con 29
7Contraseñas: mayúscula, minúscula, dígito, símbolo y 10 caractereslookaheads, fullmatchsolo PyShop2026! pasa de los 4 casos
8CSV simple: separar por coma o punto y coma sin espacios sobrantessplit, \s*4 campos limpios
9Etiquetas: quitar las etiquetas HTML de una notaclase negada«Pedido y Factura»
10Anonimizar: correos y teléfonossub, grupos, patrones previos0 correos y 0 teléfonos restantes

Pistas por bloque

Desafíos 1 a 4 (extraer y normalizar). El pedido se resuelve con una sola regex: la bandera en línea (?i) cubre mayúsculas y minúsculas y [- ]? cubre el guion, el espacio o nada; el grupo guarda solo los cinco dígitos y el formato final se arma en Python. Las fechas conviene tratarlas con tres fullmatch, uno por formato, en lugar de un patrón gigante: el formato largo usa MESES.index(mes) + 1 para obtener el número del mes. En los montos, quitar el signo de pesos, las comas y « MXN» con un solo re.sub deja una cadena que float acepta.

Desafíos 5 y 6 (reemplazar con contexto). La retrorreferencia \1 repite lo que capturó el grupo 1. Sin \b, el patrón uniría «el el» dentro de «el elefante». En las rutas, el lookahead (?=/|$) asegura que el número sea un segmento completo de la ruta; así /buscar?q=audifonos queda intacta.

import re

def normaliza_ruta(ruta):
    return re.sub(r"/\d+(?=/|$)", "/{id}", ruta)

assert normaliza_ruta("/api/pedidos/243") == "/api/pedidos/{id}"
assert normaliza_ruta("/productos/17") == "/productos/{id}"
assert normaliza_ruta("/buscar?q=audifonos") == "/buscar?q=audifonos"

Desafíos 7 a 9 (validar y limpiar). Cada condición de la contraseña es un lookahead independiente al inicio; la longitud va al final, con .{10,}. En el CSV, el espacio sobrante de 'transferencia ' aparece si el patrón solo consume espacios después del separador. Para las etiquetas, <[^>]+> no depende de codicioso o perezoso.

Desafío 10 (integrar). Reutiliza el patrón de correo y el de teléfono de los desafíos anteriores. El correo se reemplaza por ***@ más el dominio, para conservar el dato útil, y el teléfono por ** **** ****. La prueba final busca en la bandeja anonimizada cualquier correo o teléfono restante; deben quedar 0.

Qué revisar en las soluciones

  • Que cada patrón sea raw string y no use .* donde basta una clase negada.
  • Que las funciones devuelvan None cuando el texto no tiene el dato, en lugar de lanzar AttributeError.
  • Que los patrones se definan una vez, compilados y con nombre, y se reutilicen entre desafíos.
  • Que las pruebas incluyan casos que no deben coincidir, como PS-482130 o una fecha con mes 13.

Cierre

Los desafíos 1, 2, 3, 4 y 10 son las piezas del proyecto final: cuando pasen, ya tienes casi toda la limpieza de la bandeja. Guarda tus funciones en un módulo patrones.py y llévalas al proyecto con sus pruebas.

Recursos