# regex-con-python-desde-cero
Regex con Python desde Cero
Volver a la portada del cursoNotebooks de Práctica Avanzada
Sección 3 · Regex Avanzado en Python
Notebooks de Práctica Avanzada
El notebook practica-avanzada lleva a la bandeja de PyShop las herramientas de la sección: lookarounds, re.VERBOSE, sub con función, finditer con posiciones, validadores con fullmatch y patrones compilados. Es autocontenido: la primera celda de código define generar_tickets y generar_log, así que corre de principio a fin sin descargar nada y siempre produce las mismas cifras. Esta guía explica qué hace cada bloque, qué resultado esperar y en qué fijarse.
1. Preparación
Solo se usan la biblioteca estándar (re, collections.Counter, time) y Python 3.11 o superior; se probó con Python 3.13, donde el error de patrón se llama re.PatternError (en versiones anteriores solo existe re.error, y el código usa este nombre para funcionar en ambas). La celda de datos genera 600 tickets y 2000 líneas de log con semillas fijas. Ejecuta las celdas en orden: varias reutilizan patrones definidos antes.
2. Lookarounds: mirar sin consumir
Un lookahead (?=…) o un lookbehind (?<=…) exige que algo esté a la derecha o a la izquierda sin incluirlo en la coincidencia; las versiones negativas son (?!…) y (?<!…). En la bandeja hay 334 montos escritos con signo de pesos y 154 con «MXN» al final, 488 en total. El notebook los separa con dos patrones:
import re
bandeja = "\n\n".join(generar_tickets())
con_signo = re.findall(r"(?<=\$)[\d,]+(?:\.\d{2})?", bandeja)
con_mxn = re.findall(r"\d+(?:\.\d{2})?(?= MXN)", bandeja)
print(len(con_signo), len(con_mxn)) # 334 154
Después viene la trampa de la sección: \b\d+(?:\.\d{2})?\b(?! MXN) sobre «500.00 MXN y 300» devuelve ['500', '300']. El lookahead negativo falla en «500.00», pero el motor retrocede, prueba «500» y ahí sí se cumple, porque lo que sigue es «.00». El patrón correcto, \b\d+(?:\.\d+)?(?![\d.]| MXN), impide detenerse a mitad del número y devuelve ['300']. Un lookaround negativo casi siempre necesita cerrar el número por ambos lados.
La última celda del bloque intenta compilar (?<=\$\d+)x y captura el error: el lookbehind de re debe tener ancho fijo, y Python 3.13 lanza re.PatternError (alias de re.error).
3. Validador de contraseñas
Varios lookaheads al inicio comprueban condiciones independientes sobre la misma cadena. El validador exige al menos una mayúscula, una minúscula, un dígito, un símbolo y 10 caracteres:
FUERTE = r"(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[^\w\s]).{10,}"
def valida(pw):
return re.fullmatch(FUERTE, pw) is not None
for pw in ["pyshop2026", "PyShop2026", "PyShop2026!", "Py!2026a"]:
print(pw, valida(pw))
# False, False, True, False
«Py!2026a» cumple los cuatro lookaheads pero tiene 8 caracteres. Al imprimir cuál condición falla en cada caso se ve por qué conviene un mensaje por regla y no solo un False.
4. re.VERBOSE: patrones que se leen
Con re.VERBOSE los espacios del patrón se ignoran y # abre un comentario. El correo se escribe en tres líneas comentadas, usuario, arroba y dominio, y sobre la bandeja encuentra 600 correos, 352 distintos, de los cuales 138 son internos de pyshop.mx. Si necesitas un espacio literal en modo verbose, escríbelo como \ o dentro de una clase [ ].
5. sub con función y subn
La función de reemplazo recibe cada Match. El notebook la usa para conservar la inicial del usuario (v***@ejemplo.org) y con subn cuenta los reemplazos sobre la bandeja: 600 correos y 369 teléfonos. Ese conteo es la prueba de que la anonimización tocó todo lo esperado.
6. finditer con posiciones
Cada Match trae span(). En el ticket T-0003 el pedido ps-20458 ocupa las posiciones (84, 92). Con esas posiciones el notebook marca el pedido entre corchetes dentro del texto sin alterar el resto, recorriendo las coincidencias de derecha a izquierda para que los índices no se desplacen.
7. Validadores con fullmatch
Validar es comprobar el texto completo. Se construyen validadores para pedido (PS-\d{5}), teléfono normalizado (\d{10}) y fecha ISO con mes de 01 a 12 y día de 01 a 31. De las fechas de prueba 2026-02-24, 2026-13-01, 2026-02-30 y 26-02-24 pasan dos: la regex rechaza el mes 13 y el año corto, pero acepta el 30 de febrero. La regex valida la forma; el calendario lo valida datetime.date.fromisoformat.
8. Compilar
El bloque final repite 200 veces la búsqueda del pedido en los 600 tickets, con re.search y una cadena y con el patrón compilado. Los segundos dependen de la máquina, así que el notebook imprime los dos tiempos y su cociente medido en tu equipo; lo esperable es que el compilado gane por poco, porque re ya guarda en caché los patrones recientes.
Ejercicios
Al final hay cinco ejercicios con assert: extraer montos seguidos de «MXN», anonimizar teléfonos dejando los últimos 4 dígitos, validar pedidos con fullmatch, escribir el patrón del log con re.VERBOSE y comentarios, y detectar qué regla incumple cada contraseña. Si un assert falla, imprime la coincidencia y su span() antes de cambiar el patrón.
Trampas que el notebook expone
- Un lookahead negativo sin cerrar el número deja pasar fragmentos por backtracking.
- Lookbehind de ancho variable:
relo rechaza al compilar. - En modo verbose, un espacio sin escapar desaparece del patrón.
fullmatchvalida la forma, no el significado de la fecha.