Regex en 10 Minutos

Regex parece que un gato caminó sobre el teclado, pero son cinco conceptos disfrazados de sintaxis densa. Aprende los cinco, guarda la biblioteca de patrones de abajo en favoritos, y conoce las dos trampas (matching codicioso, puntos sin escapar) que causan el 90% de los bugs de regex. El audio explica el razonamiento — los símbolos están aquí en la página cuando los necesites.

🎙️ Publicado y grabado:

01El modelo: describe la forma, no el texto

Un regex describe la forma del texto: "tres dígitos, un guion, cuatro dígitos". El motor desliza esa descripción a lo largo de tu string buscando un lugar donde encaje. Ese es el mecanismo completo. Y la primera regla del regex: si buscas texto fijo, no necesitas regex — in / includes() es más rápido y no puede sorprenderte.

# forma: "dígitos, guion, dígitos" — matchea extensiones telefónicas
\d{3}-\d{4}

"call 555-0199 today"   →  matchea  "555-0199"

# pero el texto fijo NO necesita regex:
✗ re.search("error", line)     # innecesario
✓ "error" in line              # mismo resultado, sin sorpresas

02Clases de caracteres: qué se permite aquí

Una clase responde "¿qué caracteres pueden ocupar esta posición?" Tres atajos cubren la mayoría de casos — dígito, carácter de palabra, espacio en blanco — más corchetes para una lista personalizada de permitidos, y un circunflejo dentro para una lista de bloqueados.

\d    # un dígito             0-9
\w    # un carácter "palabra"  letras, dígitos, _
\s    # un espacio en blanco   espacio, tab, salto de línea
.     # CUALQUIER carácter (excepto salto de línea) — cuidado, ver 07

[abc]     # exactamente uno de: a, b, o c
[a-f0-9]  # un dígito hex (rangos con -)
[^0-9]    # un carácter que NO sea dígito (^ dentro de [] = no)

\D \W \S  # mayúsculas = lo opuesto a su gemela minúscula

03Cuantificadores: cuántas veces

Un cuantificador va después de un elemento y dice cuántas veces se repite. Cuatro cubren todo: opcional, cualquier cantidad, al menos uno, y conteos exactos entre llaves.

colou?r        # ? = 0 o 1      → color, colour
go+al          # + = 1 o más    → goal, gooooal
ab*c           # * = 0 o más    → ac, abc, abbbc
\d{4}          # exactamente 4  → 2026
\d{2,4}        # 2 a 4          → 26, 202, 2026
\d{2,}         # 2 o más

# práctica de lectura — la forma de una fecha simple:
\d{4}-\d{2}-\d{2}      # 2026-07-22

04La trampa codiciosa: .* se come todo

Los 90 segundos más importantes de esta página. Los cuantificadores son codiciosos: agarran todo lo posible mientras el match siga funcionando. Combina eso con punto-asterisco y obtienes el bug más clásico de regex — un match que abarca desde la primera apertura hasta el último cierre, tragándose todo en medio.

text:  <b>bold</b> and <i>italic</i>

<.*>      # codicioso: matchea  <b>bold</b> and <i>italic</i>  — ¡TODO!
<.*?>     # perezoso (añade ?): matchea <b>, luego </b>, luego <i>... ✓
<[^>]*>   # a menudo mejor: "cualquier cosa excepto el cierre" — rápido y explícito
La regla de oro
Cuando tu match es mucho más largo de lo esperado, te mordió la codicia. Arréglalo con el modificador perezoso (? después del cuantificador) o — generalmente mejor — reemplaza el punto con una clase negada: "cualquier cosa excepto el carácter de cierre". La clase negada dice lo que realmente quieres decir.

05Anclas: dónde, no qué

Las anclas matchean posiciones, no caracteres: inicio del string, final del string, borde de una palabra. Corrigen la clase escurridiza de bug donde tu patrón es correcto pero matchea en el lugar equivocado — validando "abc123abc" como número porque \d+ encontró el 123 en el medio.

^\d+$     # ^ inicio, $ final → el string ENTERO son dígitos
          # sin ellos: "abc123abc" pasa! (encuentra 123 dentro)

\bcat\b   # \b = borde de palabra → "cat" la palabra,
          #   no el cat en "category" o "concatenate"

^ERROR    # líneas que EMPIEZAN con ERROR (con flag multilínea)
La regla de validación
Cualquier regex usado para validar entrada de usuario (¿es un monto / ID / código válido?) debe estar anclado con inicio y final. La validación sin anclas es el bug detrás de miles de bypasses: el string del atacante solo necesita contener una pieza que parezca válida. Buscar = sin anclar; validar = anclado. Siempre.

06Grupos: captura las partes que quieres

Los paréntesis hacen dos trabajos: agrupan (para que un cuantificador o alternancia aplique al bloque entero) y capturan (la parte matcheada regresa a tu código, numerada de izquierda a derecha). La alternancia — el pipe — significa "o".

# agrupar + o:
\.(jpg|png|gif)$          # archivos que terminan en cualquiera de los tres

# captura: extraer las partes DE una fecha
(\d{4})-(\d{2})-(\d{2})
#  └ grupo 1: año  └ 2: mes  └ 3: día

# en Python:
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", text)
m.group(1)                # "2026"

# intercambiar con backreferences: "Apellido, Nombre" → "Nombre Apellido"
re.sub(r"(\w+), (\w+)", r"\2 \1", "Lovelace, Ada")

07La trampa del escape: el punto que matcheó de más

Quince caracteres tienen significados especiales. Usa uno literalmente y olvida la barra invertida, y tu patrón silenciosamente matchea más de lo que querías — el clásico es el punto sin escapar en dominios y precios, que significa "cualquier carácter".

# caracteres especiales (escapar con \ para usarlos literalmente):
.  *  +  ?  (  )  [  ]  {  }  ^  $  |  \  /

swiftgrasp.com     # el . matchea CUALQUIER carácter:
                   #   también matchea "swiftgraspXcom" ⚠
swiftgrasp\.com    # ✓ un punto literal

$19.99             # $ significa "final del string" — ¡nunca matchea!
\$19\.99           # ✓ dólar literal, punto literal
Por qué este bug sobrevive tanto
Un punto sin escapar también matchea el texto correcto — swiftgrasp.com matchea "swiftgrasp.com". Tus tests pasan. Solo que también matchea cosas que no debería, y te enteras en producción, por un caso borde raro. El sobre-matching silencioso es la razón por la que los regex necesitan tests negativos: asegura lo que no debe matchear.

08La biblioteca de patrones: copia, pega, adapta

Los patrones que todos realmente necesitan, probados y anotados. Una nota honesta primero: el "regex perfecto para email" es una trampa famosa — la especificación permite monstruosidades, así que los sistemas en producción usan un patrón simple más un email de confirmación. El pragmatismo le gana al purismo de especificación.

# email (pragmático — combinar con un mail de confirmación)
^[\w.+-]+@[\w-]+\.[\w.]+$

# URL (http/https)
https?://[^\s]+

# fecha ISO  2026-07-22
\b\d{4}-\d{2}-\d{2}\b

# hora  14:30 o 9:05
\b\d{1,2}:\d{2}\b

# número con decimales opcionales (precios, montos)
-?\d+(\.\d+)?

# IPv4 (pragmático)
\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b

# colapsar espacios repetidos → un solo espacio
\s+        # reemplazar con " "

# extraer todo entre comillas
"([^"]*)"

# color hex  #fff o #1a2b3c
#[0-9a-fA-F]{3,6}\b

09Cuándo NO usar regex

La habilidad más senior de regex es declinar usarlo. Tres reglas honestas: el texto fijo no necesita regex; las estructuras anidadas (HTML, JSON, código) no se pueden parsear con regex — eso es un límite matemático, no un problema de habilidad — usa un parser real; y si el patrón no cabe en una línea, tu yo del futuro maldecirá a tu yo del presente. Regex es un bisturí, no una motosierra.

✗ parsear HTML con regex      # usa un parser HTML (BeautifulSoup...)
✗ parsear JSON con regex      # usa json.loads — existe, está ahí mismo
✗ un regex de 200 caracteres  # divídelo en pasos, o escribe un mini parser

✓ extracción de líneas de log  # el terreno natural de regex
✓ validación (¡anclada!)      # con tests negativos
✓ buscar y reemplazar en editor # superpoder diario
La herramienta que lo cambia todo
Nunca depures un regex mirándolo fijo. Pégalo en regex101.com — explica cada símbolo, muestra matches en vivo, y te permite construir un set de pruebas. Dos minutos ahí le ganan a veinte minutos de entrecerrar los ojos. (Y el buscar-reemplazar de cada editor acepta regex — el superpoder diario que la mayoría nunca activa.)

10Chuleta

Todo lo anterior, comprimido.

# clases                       # cuantificadores
\d dígito   [abc] uno de       ?  0-1        *  0+
\w palabra  [a-z] rango        +  1+         {n,m} contado
\s espacio  [^x]  no x         añadir ? después → versión perezosa

# anclas                        # grupos
^  inicio   $  final            (x)  captura
\b borde de palabra             (a|b) o
validar = ^...$ siempre         \1 backreference

# las dos trampas
.* demasiado codicioso → .*? o [^X]*
literal . $ + ? → escapar: \. \$ \+ \?

# depurar
regex101.com — explica, prueba, guarda

# declinar amablemente
texto fijo → in/includes · HTML/JSON → parser real

Eso completa el stack de desarrollador principiante: PythonGitlínea de comandosSQLHTTPDocker → regex. Siete páginas, unos setenta minutos de audio, y un vocabulario funcional para tu primer año construyendo cosas. Ve y construye algo.