Expresiones regulares: clases, cuantificadores y grupos

Actualizado:

Una expresión regular, o regex, es un pequeño patrón que describe un texto: «cuatro dígitos, un guion, dos dígitos» o «una palabra que empieza por mayúscula». Los programas las usan para buscar, para comprobar lo que escribe el usuario y para sacar partes de una línea. Esta guía explica las piezas de un patrón, con ejemplos que puedes pegar en el probador de regex, y después las trampas: patrones que encuentran más de lo previsto, patrones que pueden tardar una eternidad y las diferencias entre los motores de JavaScript, Python y PHP. Los ejemplos usan la sintaxis de JavaScript, la que ejecutan el probador y todos los navegadores.

Caracteres que significan otra cosa

La mayoría de los caracteres de un patrón se representan a sí mismos: sol encuentra las letras s, o y l en ese orden. Catorce no, porque tienen una función en el patrón: . ^ $ * + ? ( ) [ ] { } | \ y, dentro del código JavaScript, la barra que cierra el patrón. Para buscar uno de ellos tal cual, pon una barra invertida delante.

Clases de caracteres

Una clase encuentra un carácter de un conjunto. Los corchetes enumeran el conjunto; una barra invertida y una letra dan uno ya hecho; la letra en mayúscula significa lo contrario.

PatrónEncuentra un…
[aeiou]vocal sin tilde: a, e, i, o o u
[^aeiou]carácter que no sea uno de esos, incluidos espacios y dígitos
[a-z0-9]letra minúscula de la a a la z, o un dígito
\ddígito del 0 al 9 (\D: cualquier otro)
\wletra de la A a la Z o de la a a la z, dígito o guion bajo (\W: cualquier otro)
\sespacio, tabulación, salto de línea u otro espacio en blanco (\S: cualquier otro)
.carácter salvo un salto de línea (cualquiera con la bandera s)
\p{L}letra de cualquier alfabeto, con la bandera u o v

En JavaScript, \d y \w solo conocen el alfabeto latino básico: \w+ parte España en Espa y a, y \d no encuentra el dígito arábigo oriental ٣. Con la bandera u, \p{L}+ encuentra España entera y \p{Nd} encuentra dígitos de cualquier escritura. Python 3 hace lo contrario: con texto normal, su \d y su \w ya abarcan Unicode, salvo que se active la bandera ASCII. El motor PCRE2 de PHP se queda en ASCII salvo que se activen las propiedades Unicode, por ejemplo con (*UCP) al principio del patrón.

Cuantificadores: cuántas veces

Un cuantificador dice cuántas veces puede repetirse lo que tiene delante. Se aplica a un carácter, a una clase o a un grupo entre paréntesis.

PatrónSignifica
a*cero o más
a+una o más
a?cero o una, es decir, opcional
a{3}exactamente tres
a{3,}tres o más
a{2,4}de dos a cuatro

Los cuantificadores son codiciosos: toman todo lo que pueden y solo devuelven lo que necesita el resto del patrón. En <b>negrita</b>, el patrón <.+> encuentra la cadena entera, del primer < al último >. Con un signo de interrogación detrás, el cuantificador se vuelve perezoso y toma lo mínimo: <.+?> encuentra <b> y después </b>. colou?r encuentra las dos grafías inglesas, color y colour, y \d{3,} encuentra números de tres cifras o más.

Anclas y límites de palabra

Las anclas encuentran una posición, no un carácter. ^ es el principio del texto y $ el final; con la bandera m pasan a ser el principio y el final de cada línea. \b es un límite de palabra, el punto entre un carácter de palabra y cualquier otra cosa, así que \bsol\b encuentra sol como palabra pero no dentro de soleado. Sin anclas, un patrón usado para validar también acepta texto con caracteres de más alrededor: \d{4} encuentra cuatro dígitos dentro de abc12345, mientras que ^\d{4}$ solo acepta exactamente cuatro dígitos.

Grupos, alternativas y referencias

Los paréntesis agrupan parte de un patrón para que un cuantificador o una alternativa se aplique a todo él, y capturan el texto encontrado para que un programa pueda leerlo: (\d{4})-(\d{2})-(\d{2}) captura año, mes y día por separado. (?:…) agrupa sin capturar, y (?<anio>\d{4}) da nombre a la captura.

La barra vertical significa «o», y es lo que menos prioridad tiene: ^sol|mar$ significa «sol al principio» o «mar al final», así que encuentra sol en soleado y mar en amar. Para decir «el texto entero es sol o mar», agrupa las alternativas: ^(?:sol|mar)$.

Una referencia hacia atrás encuentra el mismo texto que un grupo ya capturó: (\w)\1 encuentra una letra seguida de sí misma, rr y ll en carretilla, y \k<nombre> hace lo mismo con un grupo con nombre.

Lookahead y lookbehind

Un lookaround comprueba lo que viene antes o después de una posición sin incluirlo en la coincidencia. (?=…) exige que algo siga, (?!…) lo prohíbe; (?<=…) exige que algo preceda, (?<!…) lo prohíbe. Sirven para sacar un número por su unidad o su moneda, o para acumular varias condiciones sobre el mismo texto.

Banderas

Las banderas cambian cómo se aplica todo el patrón. En JavaScript van tras la barra de cierre, como en /sol/gi; en el probador tienen su propio campo.

BanderaEfecto
gencontrar todas las coincidencias, no solo la primera
ino distinguir mayúsculas de minúsculas
m^ y $ funcionan en cada línea
sel punto también encuentra saltos de línea
umodo Unicode: \p{…}, y los emojis cuentan como un carácter
vmodo Unicode con operaciones de conjuntos en las clases; úsala en lugar de u
ypegajosa: solo busca donde terminó la coincidencia anterior
dguardar dónde empieza y termina cada grupo

Comprobar correos, fechas y otros formatos

Una regex puede comprobar la forma de un dato, no si es real. El estándar HTML define lo que acepta un <input type="email"> con un patrón propio, y dice abiertamente que se aparta a propósito del RFC 5322, el estándar del formato de correo, que permite formas como nombres entre comillas con espacios que casi nadie usa. Acepta ana@example.com y también ana@localhost; rechaza ana@my_domain.example, porque un nombre de dominio no puede llevar guion bajo. Si el buzón existe, solo lo dice un mensaje.

Con las fechas pasa algo parecido: ^\d{4}-\d{2}-\d{2}$ acepta 2026-02-31, que no existe. Comprueba la forma con el patrón y deja que una función de fechas decida si la fecha es válida. Y no analices HTML ni JSON con expresiones regulares: las estructuras anidadas necesitan un analizador.

Cuando un patrón no termina nunca

La mayoría de los motores, incluidos los de JavaScript, Python y PHP, trabajan con retroceso (backtracking): cuando un camino falla, vuelven atrás y prueban otra forma de repartir el texto entre las partes del patrón. Un grupo que repite algo que a su vez se repite, como ^(a+)+$, puede repartirse de un número de formas que se duplica con cada carácter más. En una línea de aes que termina en signo de exclamación el patrón nunca puede coincidir, pero el motor prueba todos los repartos antes de rendirse. OWASP lo llama denegación de servicio por expresiones regulares, ReDoS, y cita patrones como (a+)+$, ([a-zA-Z]+)*$ y (a|aa)+$.

La solución es quitar la ambigüedad: ^a+$ describe el mismo texto y falla al instante. Evita cuantificadores anidados y alternativas que puedan encontrar los mismos caracteres, y no ejecutes nunca un patrón de un usuario sin límite de tiempo. El probador de regex ejecuta cada búsqueda en un worker aparte y la detiene al cabo de medio segundo, así que un patrón así se señala en lugar de colgar la página.

Probador de regex

No todos los motores son iguales

Lo básico funciona casi en todas partes, pero los detalles cambian entre lenguajes. Un patrón escrito para un motor debe probarse en el otro antes de confiar en él.

FunciónJavaScriptPython (re)PHP (PCRE2)
Grupo con nombre(?<nombre>…)(?P<nombre>…)las dos formas
\d y \wsolo ASCIIUnicode por defectoASCII salvo con UCP
Cuantificadores posesivos y grupos atómicos (a++, (?>…))nosí, desde Python 3.11sí
Banderas en línea como (?i)solo la forma acotada (?i:…), desde ECMAScript 2025sísí

El lookbehind también cambia: JavaScript acepta uno de longitud variable, como (?<=[a-z]+), mientras que Python exige una anchura fija y lo rechaza. Python además escribe las barras invertidas de otro modo en el código: una cadena cruda, r"\d+", las conserva tal cual, mientras que los patrones de JavaScript entre barras no necesitan duplicarlas. En una cadena de JavaScript pasada a new RegExp(), cada barra invertida debe escribirse dos veces.

Preguntas frecuentes

¿Por qué mi patrón solo encuentra una coincidencia?

En JavaScript la búsqueda se detiene en la primera coincidencia salvo que se use la bandera g. En el probador, añade g a las banderas.

¿Por qué \w no encuentra letras con tilde ni la ñ?

Porque en JavaScript \w significa solo de la A a la Z, de la a a la z, dígitos y guion bajo. Usa \p{L} con la bandera u para letras de cualquier alfabeto.

¿Cómo busco un punto, un paréntesis o un signo de interrogación?

Pon una barra invertida delante: \. \( \? y así sucesivamente. Dentro de corchetes la mayoría pierde su significado, así que [.?] encuentra un punto o un signo de interrogación.

¿Puede una expresión regular validar un correo?

Solo su forma. El patrón del estándar HTML es una buena elección para formularios; si la dirección recibe correo solo se comprueba enviando un mensaje.

¿Por qué mi patrón colgó el programa?

Probablemente repite un grupo que a su vez se repite, como (a+)+, y el texto casi coincide. Reescríbelo sin cuantificadores anidados y ejecuta los patrones de usuarios con límite de tiempo.

Referencias

  1. MDN Web Docs — Regular expressions (JavaScript guide)
  2. MDN Web Docs — Regular expression syntax cheat sheet
  3. ECMAScript® Language Specification — RegExp (Regular Expression) Objects
  4. TC39 — Finished proposals (RegExp modifiers and duplicate named groups: ECMAScript 2025)
  5. Python documentation — re: regular expression operations
  6. PCRE2 — pcre2pattern: syntax and semantics of the regular expressions
  7. OWASP — Regular expression Denial of Service (ReDoS)
  8. WHATWG HTML Standard — Valid email address
  9. RFC 5322 — Internet Message Format (October 2008)

Guías relacionadas