Expresiones regulares a la vista
·
Resumen del curso
1
El pago desaparecido: buscar el texto tal cual
2
El coche que se dio a la fuga: clases de caracteres
3
La guía telefónica rota: cuantificadores
4
Los registros falsos: anclas y validación
5
Fechas por todas partes: grupos y alternativas
6
El acceso de las 3 de la madrugada: grupos con nombre y objetos Match
7
La víspera de la noticia: sustitución y división
8
El desafío del Backtracker: codicioso, perezoso y posesivo
9
Las reglas de la caja fuerte: lookaround
10
El mismo modus operandi: retrorreferencias y condicionales
11
La regex ilegible: flags y compilación
12
El Backtracker, desenmascarado: repaso y un tokenizador
CASE-009
Grep & Co. Agencia de Detectives de Datos
Expediente
Cliente
La directora Han Byeol
Pruebas
La vieja caja fuerte de la agencia, seis candidatas a nueva contraseña y el libro de cuentas que hay dentro.
Para cerrar el caso
Comprobar con un solo patrón las reglas de la nueva contraseña (8 caracteres o más, con al menos un dígito, una minúscula y un carácter especial) y poner separadores de miles en las cifras del libro de cuentas.
La directora se agacha frente a la vieja caja fuerte del rincón. «Lo de la caja fuerte es solo para asustarnos. Aun así, hoy cambiamos la contraseña. Y esta vez, cumpliendo las reglas».
La nueva contraseña tiene que cumplir tres reglas, en cualquier orden. La directora las ha anotado en coreano: 8 caracteres o más; al menos un dígito, una minúscula y un carácter especial; y comprobarlo todo con una sola regex.
규칙 1. 8자 이상
규칙 2. 숫자, 소문자, 특수문자가 각각 하나 이상
규칙 3. 이 모든 걸 정규식 하나로 검사한다
후보:
vault2026!
vault2026
VAULT2026!
v!2
longpassword!
safe#2026boxTe viene a la cabeza la frase de la tarjeta: «Si son capaces de comprobarlas todas desde el mismo sitio». La sintaxis de hoy es justo eso.
Recuerda ^, $ y \b de la lección 4. No se comían ningún carácter: solo comprobaban una posición, del tipo «¿esto es el principio?» o «¿esto es un límite de palabra?». A este tipo de coincidencia se le llama coincidencia de ancho cero (zero-width).
re.findall(r"\b", "hi yo") # ['', '', '', '']
re.sub(r"\b", "|", "hi yo") # '|hi| |yo|'Lo que encontró \b son cuatro cadenas vacías, es decir, cuatro posiciones. El lookaround de hoy es la sintaxis que convierte esa «comprobación de posición» en la condición que tú quieras.
X(?=Y) busca «una X seguida de Y». La Y solo se comprueba; no forma parte de la coincidencia. Esto se llama lookahead (búsqueda hacia delante).
re.findall(r"\d+(?=원)", "3000원짜리 5개, 합계 15000원") # ['3000', '15000']La frase es coreana: «artículo de 3000 원, 5 unidades, total 15000 원» (원 es el won, la moneda de Corea, y 개 significa «unidades»). El 5 de 5개 quedó fuera porque no le sigue 원, y los números encontrados no incluyen el 원. Es perfecto cuando buscas «números que terminan en 원» pero solo quieres sacar el número.
Laboratorio de pruebas
re.search(r"", text)
Valor devuelto
X(?!Y) es lo contrario: «una X a la que no sigue Y». Se llama lookahead negativo.
re.findall(r"\b(?!tmp)\w+", "tmp_log report tmpfile final") # ['report', 'final']
re.findall(r"\d{3}(?!\d)", "12345 678") # ['345', '678']tmp»: justo después del límite de palabra, comprueba que no venga tmp.Las condiciones del tipo «tiene que tener esto, y esto, y esto otro», como las reglas de la contraseña, se escriben poniendo lookaheads en fila.
pw = r"(?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}"| Pieza | Qué comprueba |
|---|---|
(?=.*\d) | Hay un dígito en algún sitio |
(?=.*[a-z]) | Hay una minúscula en algún sitio |
(?=.*[^\w\s]) | Hay un carácter especial (algo que no es letra, dígito, guion bajo ni espacio) en algún sitio |
.{8,} | Se come de verdad 8 caracteres o más |
Los tres lookaheads se comprueban desde el mismo sitio (el principio). Como no se comen ningún carácter, al terminar uno la posición sigue igual y la siguiente condición vuelve a empezar desde el principio. Por eso, ponerlos seguidos equivale a un «Y» (AND).
cands = ["vault2026!", "vault2026", "VAULT2026!", "v!2", "longpassword!", "safe#2026box"]
[c for c in cands if re.fullmatch(pw, c)] # ['vault2026!', 'safe#2026box']Laboratorio de pruebas
re.search(r"", text)
Valor devuelto
El consejo de Dot
El lookahead solo echa un vistazo hacia delante, sin mover las patas. Como yo, que me siento en el alféizar a mirar fuera pero no salto. Por eso, por muchas veces que mire, sigo en el mismo sitio.
Si das la vuelta a la dirección, tienes el lookbehind (búsqueda hacia atrás). (?<=Y)X es «una X precedida de Y» y (?<!Y)X es «una X no precedida de Y».
re.findall(r"(?<=\$)\d+", "$30 and 40 and $5") # ['30', '5']
re.findall(r"(?<!\$)\b\d+", "$30 and 40 and $5") # ['40']El lookbehind tiene una limitación: en el re de Python, la longitud que se mira hacia atrás tiene que ser fija.
re.compile(r"(?<=a+)b") # PatternError: look-behind requires fixed-width pattern
re.compile(r"(?<=ab|cd)e") # correcto: las dos opciones tienen 2 caracteres
re.compile(r"(?<=a|bc)d") # PatternError: look-behind requires fixed-width patternPuede haber varias opciones siempre que todas tengan la misma longitud. Si no, divide el lookbehind en dos o agrúpalos por separado, como en (?:(?<=a)|(?<=bc))d.
Laboratorio de pruebas
re.search(r"", text)
Valor devuelto
En el libro de cuentas de la caja fuerte los números van pegados, como 1234567, y cuesta leerlos. Basta con encontrar las posiciones donde va una coma y meterla ahí. Como se trata de encontrar posiciones, el lookaround es la herramienta ideal.
re.sub(r"(?<=\d)(?=(?:\d{3})+(?!\d))", ",", "1234567 and 89 and 1000")
# '1,234,567 and 89 and 1,000'Se lee así: «una posición con un dígito delante ((?<=\d)) y, detrás, uno o más grupos de tres dígitos ((?:\d{3})+) tras los cuales se acaban los dígitos ((?!\d))». Esa posición no es un carácter, así que sub no borra nada: solo intercala la coma.
Si pones un grupo dentro de un lookahead, también puedes encontrar coincidencias solapadas. El truco es avanzar la posición de una en una y sacar con el grupo los dos caracteres que hay en ese punto.
re.findall(r"(?=(\w\w))", "abc") # ['ab', 'bc']Laboratorio de pruebas
re.search(r"", text)
Valor devuelto
Terminas el validador y filtras las candidatas. En la salida, 통과 significa «aprobada» y 탈락, «descartada».
pw = re.compile(r"(?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}")
for c in cands:
print(f"{c:<14} {'통과' if pw.fullmatch(c) else '탈락'}")
# vault2026! 통과
# vault2026 탈락
# VAULT2026! 탈락
# v!2 탈락
# longpassword! 탈락
# safe#2026box 통과La directora no elige ninguna de las dos que han pasado. «En cuanto está en una lista de candidatas, ya no es una contraseña». Luego elige ella misma, sin que nadie la vea, una contraseña nueva que cumple las reglas, y guarda solo el validador en la caja de herramientas común de la agencia.
Informe de caso cerrado — Se creó una herramienta que comprueba las reglas de la contraseña de la caja fuerte con tres lookaheads. Solo dos de las seis candidatas cumplieron las reglas. La directora cambió la contraseña por su cuenta. Se añadieron separadores de miles a las cifras del libro de cuentas.
"price: 1200won, tax: 120won", saca con un lookahead solo los números que van delante de won.re.findall(r"(?<!\d)\d{2}(?!\d)", "1 22 333 44"). ¿Por qué no sale ningún trozo de 333?El rastro del Backtracker
(a+)+$
La caja fuerte la dejo en paz. A cambio, le he enviado tres cartas al inspector Kang, de la comisaría. ¿Podrán demostrar que las escribió la misma persona? Las manías quedan en las letras.
La libreta de la directora
El lookaround es una coincidencia de ancho cero: no come caracteres, solo comprueba una posición (de la familia de ^ $ \b).
X(?=Y): X seguida de Y. X(?!Y): X no seguida de Y.
(?<=Y)X: X precedida de Y. (?<!Y)X: X no precedida de Y. El lookbehind solo admite longitud fija.
Lookaheads seguidos = AND: (?=.*\d)(?=.*[a-z])(?=.*[^\w\s]).{8,}
Si sub encuentra posiciones, intercala sin borrar nada: separadores de miles.
Con un grupo dentro de un lookahead, como (?=(\w\w)), puedes sacar coincidencias solapadas.
← Anterior
Lección 8 · El desafío del Backtracker: codicioso, perezoso y posesivo
Siguiente →
Lección 10 · El mismo modus operandi: retrorreferencias y condicionales
Recibe avisos de nuevas lecciones
Te avisaremos por correo cuando este curso tenga lecciones nuevas o se abra un curso de continuación.
R
ReflexKR
Aprende Python y Reflex haciendo. Todos los ejemplos se ejecutaron y verificaron en Reflex 0.10.0.
ReflexKR es gratis y sin banners publicitarios. Si te ayudó, puedes apoyarlo con un café. ☕ Invítanos un café
Aviso de afiliados© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Preguntas y respuestas
Pregunta lo que quieras sobre esta lección. Aquí se reúnen las preguntas de todas las versiones de idioma de esta página.