Regex en JavaScript: sintaxis, flags y los métodos con los que trabajan

Las expresiones regulares de JavaScript permiten buscar, validar y transformar texto con patrones potentes. La sintaxis es compacta, los flags cambian el comportamiento de búsqueda, y los métodos de string y de RegExp que las consumen tienen matices importantes que conviene conocer para evitar bugs.

Crear una regex: literal vs RegExp()

Los literales de regex se compilan en tiempo de parse y son más eficientes para patrones fijos. El constructor RegExp() acepta strings y es necesario cuando el patrón se construye dinámicamente:

// Literal: /patrón/flags — se compila una vez
const emailRegex = /^[w.+-]+@[w-]+.[a-zA-Z]{2,}$/i;

// Constructor: para patrones dinámicos
function crearBuscador(termino) {
  // Escapar caracteres especiales en el término
  const escapado = termino.replace(/[.*+?^${}()|[]\]/g, '\$&');
  return new RegExp(escapado, 'gi');
}

const buscar = crearBuscador('precio (EUR)');
'El precio (EUR) es 29.99'.match(buscar);
// ['precio (EUR)']

Flags más importantes

const texto = 'JavaScript es un lenguaje.nJavaScript es popular.';

// i — insensible a mayúsculas
'Hola MUNDO'.match(/hola/i);    // ['Hola']

// g — global (busca todas las coincidencias, no solo la primera)
texto.match(/javascript/gi);    // ['JavaScript', 'JavaScript']

// m — multilinea: ^ y $ coinciden con inicio/fin de cada línea
texto.match(/^javascript/gim);  // ['JavaScript', 'JavaScript']

// s — dotAll: . también coincide con saltos de línea
/inicio.fin/s.test('inicionfin');  // true

// u — Unicode: soporte correcto para emojis y caracteres Unicode
'?'.match(/./u);   // ['?'] (un solo match)
'?'.match(/./);    // ['?', '?'] (sin u: ve dos unidades de código)

// Combinar flags:
const global_insensible = /patrón/gi;

Métodos: test, match, matchAll, replace, split

const email = '[email protected]';

// test(): devuelve boolean
/^[w.]+@[w]+.w+$/.test(email);  // true

// match(): devuelve array con la primera coincidencia (o todas con g)
const texto = 'Precios: 10€, 25€, 100€';
texto.match(/d+€/);   // ['10€']
texto.match(/d+€/g);  // ['10€', '25€', '100€']

// matchAll(): iterador de todas las coincidencias con grupos
const html = 'Uno Dos';
const regex = /([^<]+)/g;
const matches = [...html.matchAll(regex)];
matches.forEach(m => console.log(`Enlace: ${m[2]} ? ${m[1]}`));
// Enlace: Uno ? https://uno.com
// Enlace: Dos ? https://dos.com

// replace(): reemplazar
'hola mundo'.replace(/o/g, '0');      // 'h0la mund0'
'ana, luis'.replace(/(w+)/g, '[$1]'); // '[ana], [luis]'

// replace con función:
'2026-06-26'.replace(/(d{4})-(d{2})-(d{2})/, (m, y, mon, d) =>
  `${d}/${mon}/${y}`
);  // '26/06/2026'

// split():
'a, b,,c'.split(/,s*/);  // ['a', 'b', '', 'c']

Grupos de captura nombrados

Los grupos nombrados ((?<nombre>...)) hacen el código mucho más legible que los índices numéricos:

const fechaRegex = /(?<año>d{4})-(?<mes>d{2})-(?<dia>d{2})/;
const match = '2026-06-26'.match(fechaRegex);

console.log(match.groups.año);  // '2026'
console.log(match.groups.mes);  // '06'
console.log(match.groups.dia);  // '26'

// En replace con grupos nombrados:
'2026-06-26'.replace(fechaRegex, '$<dia>/$<mes>/$<año>');
// '26/06/2026'

Lookahead y lookbehind

// Lookahead positivo (?=...): coincidir si va seguido de
'100px 200em 50%'.match(/d+(?=px)/g);  // ['100']

// Lookahead negativo (?!...): coincidir si NO va seguido de
'100px 200em'.match(/d+(?!px)b/g);   // ['200']

// Lookbehind positivo (?<=...): coincidir si va precedido de
'precio: 100€ y 200€'.match(/(?<=€)d+/g);  // null
'precio: 100€ y 200€'.match(/d+(?=€)/g);    // ['100', '200']

La trampa de lastIndex con el flag g

Las regex con el flag g tienen estado: el índice de inicio de la siguiente búsqueda se guarda en lastIndex. Esto causa bugs al reutilizar la misma regex en múltiples búsquedas:

const regex = /d+/g;

console.log(regex.test('abc 123'));  // true
console.log(regex.lastIndex);        // 7 (guarda la posición)

// Segunda llamada empieza desde la posición 7:
console.log(regex.test('456 def'));  // false (¡bug!)
console.log(regex.lastIndex);        // 0 (se resetea tras fallar)
console.log(regex.test('456 def'));  // true (ahora sí)

// Solución: crear la regex cada vez, o resetear lastIndex
regex.lastIndex = 0;
// O usar métodos de string (match, matchAll) en lugar de regex.test()

Para validaciones sencillas, los métodos de string (includes, startsWith, endsWith) son más claros que regex. Reserva las expresiones regulares para patrones que realmente requieran su potencia.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP