Skip to content

Guide

Hoja de referencia de Regex: patrones comunes que todo desarrollador necesita

Veinticinco patrones que realmente usarás, la distinción greedy/lazy que causa la mitad de los errores de regex, y dónde JavaScript regex difiere de PCRE.

By Published

Un regex funcional no es una línea que memorizas; es una línea más los supuestos sobre tu input y tu variante. Esta hoja de referencia empareja cada patrón con lo que realmente coincide, los casos extremos que omite y en qué motores de regex funciona. Introduce cualquiera de ellos en nuestro probador de regex en vivo para ver coincidencias y capturas de forma interactiva.

Notación usada a continuación

Los patrones se muestran sin los delimitadores /.../ excepto cuando importan las flags. Asume que ^ y $ están anclados a un solo valor (el campo completo), no multilínea. Cuando un patrón usa características que no son universales, la nota de variante indica en qué motores funciona. Cuando hay tanto una forma permisiva como una estricta, se dan ambas.

Identificadores y nombres

Email — permisivo

^[^\s@]+@[^\s@]+\.[^\s@]+$

Tres clases de caracteres separadas por @ y ., ninguna de las cuales contiene espacios en blanco u otro @. Acepta casi todos los emails del mundo real y rechaza los errores tipográficos más obvios. No validará contra RFC 5322 — las partes locales entre comillas y los dominios IP literales se filtran o se rechazan dependiendo del caso.

Email — especificación de formulario HTML5

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$

El patrón que WHATWG especifica para input type=“email“de HTML. Más estricto que la forma permisiva pero aún no afirma cobertura completa de RFC 5322 — la especificación dice explícitamente “incumplimiento deliberado.” Úsalo cuando quieras coincidir con el comportamiento del navegador.

URL — solo HTTPS

^https://[^\s/$.?#].[^\s]*$

URL HTTPS permisiva. Rechaza la basura obvia pero acepta cualquier cosa después del host que no sea espacio en blanco. Para validación real, delega a new URL() en el lenguaje anfitrión; regex es para filtrar inputs, no para analizarlos.

Slug (identificador seguro para URL)

^[a-z0-9]+(?:-[a-z0-9]+)*$

Letras minúsculas y dígitos con guiones simples entre grupos. Sin guiones iniciales o finales, sin guiones dobles. Esta es la forma de slug que usa todo CMS.

Nombre de usuario — alfanumérico y guión bajo, 3-20 caracteres

^[A-Za-z0-9_]{3,20}$

UUID (cualquier versión)

^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$

UUID v4 (estricto)

^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$

Aplica el 4 en la posición 13 y los bits de variante en la posición 17 (uno de 8, 9, a, b). Úsalo cuando te importe la versión, no solo la forma.

Números, dinero, códigos

Entero (con signo)

^-?\d+$

Número decimal (con signo, parte fraccionaria opcional)

^-?\d+(?:\.\d+)?$

Importe en moneda (estilo EE. UU.)

^\$?\d{1,3}(?:,\d{3})*(?:\.\d{2})?$

Signo de dólar opcional, separadores de miles cada tres dígitos, centavos de dos decimales opcionales. No maneja negativos; para uso contable, antepone ^-? o envuelve entre paréntesis.

Color hex (3, 4, 6 u 8 dígitos)

^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

Las formas de 4 y 8 dígitos incluyen un canal alpha (#RRGGBBAA) compatible con CSS Color Level 4 y todos los navegadores modernos.

Versión semántica (semver 2.0.0)

^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$

Este es el regex canónico publicado en semver.org. Captura major, minor, patch, pre-release opcional y metadatos de compilación opcionales. Rechaza correctamente los ceros iniciales en componentes numéricos.

Fechas y horas

Fecha ISO 8601 (AAAA-MM-DD)

^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$

Restringe el mes a 01-12 y el día a 01-31. No valida que el día exista en el mes dado (el 30 de febrero pasa). Para validación de fecha real, analiza con el lenguaje anfitrión y comprueba si hay errores.

Marca de tiempo ISO 8601 con zona horaria

^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$

Acepta Z para UTC o un desplazamiento numérico como +02:00. Permite segundos fraccionarios opcionales.

Hora HH:MM en formato 24 horas

^(?:[01]\d|2[0-3]):[0-5]\d$

Direcciones de red

IPv4

^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$

Rango de octetos estrictamente 0-255. Rechaza ceros iniciales como 192.168.001.001 (que es inequívoco para los humanos pero algunos sistemas interpretan como octal, por lo que el rechazo es defendible).

IPv6 — práctico

^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$

Coincide con la forma canónica de ocho grupos. No coincidirá con IPv6 con compresión :: o con IPv4 incrustado como ::ffff:192.0.2.1. El regex completo de RFC 4291 tiene más de cien caracteres; para uso en producción, delega al equivalente inet-pton de tu lenguaje.

Dirección MAC

^(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}$

Número de puerto

^(?:6553[0-5]|655[0-2]\d|65[0-4]\d{2}|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$

0-65535, estrictamente acotado.

Números de teléfono

Teléfono de EE. UU. — permisivo

^(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$

+1 opcional, paréntesis opcionales alrededor del código de área, separadores opcionales de guion, punto o espacio. Acepta los formatos comunes de EE. UU.; rechaza números no estadounidenses.

Teléfono internacional (E.164)

^\+[1-9]\d{1,14}$

E.164 es la especificación ITU: + inicial, código de país comenzando con no-cero, longitud total de 2-15 dígitos incluyendo el código de país. Sin espacios, sin paréntesis. Este es el formato que espera cada gateway de SMS y la mayoría de los CRM.

Cadenas y estructura

Cadena solo de espacios en blanco

^\s*$

Eliminar espacios en blanco iniciales/finales (reemplazar con vacío)

^\s+|\s+$

Colapsar múltiples espacios a uno (reemplazar con un solo espacio)

\s{2,}

Coincidir contenido entre corchetes (lazy)

\[([^\]]*)\]

Captura caracteres que no son un corchete de cierre — la clase de caracteres negada es la forma más limpia de hacer “todo hasta el siguiente delimitador” sin ser greedy.

Comportamiento de cuantificadores

Greedy (el predeterminado)

*, +, ? y {n,m} coinciden tanto como sea posible de forma predeterminada, luego retroceden para encontrar una coincidencia para el resto del patrón. En <b>hola</b><b>adiós</b>, el patrón <b>.*</b> coincide con toda la cadena, no con el primer par de etiquetas.

Lazy (sufijo ?)

Añade un ? para hacer que un cuantificador coincida lo menos posible. <b>.*?</b> coincide solo con <b>hola</b>, que es casi siempre lo que querías.

Cuantificadores posesivos y grupos atómicos

Los cuantificadores posesivos (*+, ++) y los grupos atómicos ((?>...)) se niegan a retroceder una vez coincididos. Eliminan el retroceso catastrófico en inputs patológicos. PCRE, Java y Ruby los admiten; JavaScript no (usa una solución alternativa como un lookahead con una retroreferencia).

Lookahead y lookbehind

Los lookarounds afirman una condición sin consumir caracteres. Son de anchura cero.

  • Lookahead positivo (?=...) — “seguido de.” \d+(?=px) coincide con dígitos que van seguidos de pxsin incluir el px en la coincidencia.
  • Lookahead negativo (?!...) — “no seguido de.” foo(?!bar) coincide con foo no seguido de bar.
  • Lookbehind positivo (?<=...)— “precedido por.”
  • Lookbehind negativo (?<!...)— “no precedido por.”

JavaScript admite lookahead en todas las versiones, lookbehind solo a partir de ES2018. Muchos motores más antiguos (y la versión de V8 en algunas compilaciones de Node incluidas) limitan los lookbehinds a patrones de ancho fijo; PCRE y el módulo regex de Python permiten ancho variable.

Diferencias de variante que vale la pena recordar

  • JavaScript: sin cuantificadores posesivos, sin grupos atómicos, lookbehind desde ES2018. La flag g (global) hace que String.match devuelva todas las coincidencias pero String.replace se comporte diferente — el rincón más lleno de errores del regex de JS.
  • PCRE (Compatible con Perl): el superconjunto de características. Usado por PHP, nginx, muchas herramientas de línea de comandos. Patrones recursivos, condicionales, cuantificadores posesivos, grupos atómicos, capturas con nombre — todo admitido.
  • Python: el módulo estándar re es cercano a PCRE menos algunas características. El módulo de terceros regex añade el resto más lookbehinds de ancho variable y grupos atómicos.
  • Go (RE2): deliberadamente de tiempo lineal. Sin retroreferencias, sin lookaround. Más lento en patrones simples, inmune al retroceso catastrófico. El crate regex de Rust es de la misma familia.
  • .NET: similar a PCRE, más algunas características únicas como los grupos de equilibrio (que te permiten realmente coincidir con corchetes anidados — de una manera que ninguna otra variante puede).

Una flag que vale la pena destacar en todas las variantes: Unicode escapes de propiedades (\p{Letter}, \p{Number}, \p{Script=Greek}) coinciden por categoría de codepoint en lugar de por byte raw. JavaScript necesita la flag u, PCRE necesita (*UCP) o el modificador /u, Python los admite en el módulo de terceros regex. Sin ellos, \w significa solo ASCII [A-Za-z0-9_]y tu patrón de “coincidir cualquier nombre” rechaza silenciosamente la mitad del mundo.

Los patrones que nunca debes escribir

  • Análisis de HTML. Usa un analizador real (DOMParser en el navegador, BeautifulSoup en Python, go-html en Go). Regex puede extraer un solo atributo de una forma bien conocida, nada más.
  • Análisis de JSON. Cada lenguaje tiene JSON.parse. Úsalo.
  • Análisis de lenguajes de programación. Usa un combinador de analizadores o una gramática real.
  • Cualquier cosa que necesite coincidir con delimitadores anidados. Los lenguajes regulares clásicos no pueden contar. Usa un analizador.

La conclusión honesta

Regex es una herramienta afilada con un dominio pequeño y bien entendido: cadenas de forma fija, filtrado de entrada simple, buscar y reemplazar en editores de texto. Los patrones en esta hoja de referencia cubren el 80% de los casos que surgen en el código cotidiano. Para el 20% que parece regex pero no lo es — estructuras anidadas, coincidencia de lenguaje natural, validación semántica — usa un analizador.

Y cuando escribas un regex, pégalo en nuestro probador con tres inputs representativos y tres inputs patológicos antes de confirmarlo. El patrón que funciona en tu único caso de prueba es el patrón que derriba producción en el de otra persona.

Frequently asked questions

¿Por qué mi regex de email rechaza direcciones válidas?
Porque la gramática de RFC 5322 para direcciones de email válidas tiene más de una página e incluye construcciones como partes locales entre comillas ("nombre de usuario"@example.com) y dominios IP literales (usuario@[192.168.0.1]). La mayoría de los 'regex de email' aplican un pequeño subconjunto común. Para validación real, envía un email de confirmación — el regex solo puede filtrar errores tipográficos obvios.
¿La variante de regex realmente difiere tanto entre lenguajes?
Sí. JavaScript admite lookahead pero solo obtuvo lookbehind en 2018 (ES2018) y grupos con nombre en la misma versión. Python usa re para regex básico y regex para características avanzadas como patrones recursivos. PCRE tiene más características y es el más cercano a un 'superconjunto de regex'. .NET tiene sus propias peculiaridades. Siempre prueba en el entorno de ejecución real, no en regex101 con la variante incorrecta seleccionada.
Cuantificadores greedy vs lazy — ¿cuál quiero?
Greedy (el predeterminado) coincide tanto como sea posible; lazy (sufijo ?) coincide lo menos posible. Para .* dentro de etiquetas HTML, casi siempre quieres lazy: .*? — de lo contrario <b>hola</b><b>adiós</b> coincide con todo desde el primer <b> hasta el último </b>. Para análisis numérico donde la longitud del campo es conocida, greedy generalmente está bien.
¿Cuándo no debo usar regex?
Al analizar HTML, JSON, YAML, lenguajes de programación o cualquier cosa con estructura anidada. Regex es una herramienta para lenguajes regulares; en el momento en que necesitas contar o recursar (hacer coincidir corchetes anidados, hacer coincidir etiquetas de apertura/cierre), usa un analizador real. La respuesta de Stack Overflow de 'analizar HTML con regex' se convirtió en un clásico de culto porque el consejo es correcto.
¿Cuál es la forma más segura de validar una URL?
Pásala al constructor URL en el lenguaje real — new URL(input) de JavaScript, urllib.parse.urlparse de Python, java.net.URI de Java. Estos implementan los RFC relevantes y manejan casos extremos (dominios internacionales, rangos de puertos, validación de esquema) que un regex no manejará. Usa regex solo para filtrar la plausibilidad sintáctica antes de esa llamada.
¿Por qué mi regex es tan lento en ciertos inputs?
Retroceso catastrófico. Los patrones con cuantificadores anidados o superpuestos — como (a+)+ o (.*).* — pueden tomar tiempo exponencial en ciertos inputs. La interrupción global de Cloudflare en julio de 2019 fue un regex que hacía exactamente esto. Mitigaciones: evita cuantificadores anidados, usa grupos atómicos (?>...) o cuantificadores posesivos en variantes que los admitan, o usa un motor de tiempo lineal como el regex de Rust o RE2 de Google.

Related

Published May 31, 2026