6 de julio de 2026

JavaScript match() y matchAll(): extraer texto con expresiones regulares (2026)

Foto de Marco Orta Marco Orta | 8 min de lectura
Compartir
Código JavaScript extrayendo un email de un texto con el método match y una expresión regular

Con replace() sustituyes texto y con split() lo divides. Falta la tercera operación fundamental de manipulación de cadenas: extraer información. Para eso están match() y matchAll(), los dos métodos que combinan strings con expresiones regulares para sacar exactamente los datos que te interesan.

Extraer todos los emails de un texto, capturar la fecha de un log, sacar los hashtags de un comentario o parsear los valores de una plantilla: todo eso son trabajos para match() y matchAll(). En esta guía vas a ver la diferencia crítica entre ambos (spoiler: el flag g lo cambia todo), cómo usar grupos de captura con nombre y los errores que hacen perder coincidencias silenciosamente.

1. Qué hacen match() y matchAll()

Ambos son métodos del objeto String que buscan coincidencias de una expresión regular dentro de una cadena y devuelven lo que encuentran. La diferencia está en cuánto devuelven:

  • match() — devuelve un array con la coincidencia (o todas, si usas el flag g), o null si no hay ninguna.
  • matchAll() — devuelve un iterador con todas las coincidencias, incluyendo sus grupos de captura y posiciones. Siempre requiere el flag g.

Regla mental: si solo quieres saber si hay coincidencia o extraer una sola, match() basta. Si necesitas todas las coincidencias con sus grupos de captura, matchAll() es la herramienta correcta.

2. String.prototype.match()

cadena.match(regexp)

El comportamiento de match() cambia por completo según tenga o no el flag global g. Este es el detalle que más confusión causa:

Sin flag g: una coincidencia con todos los detalles

const texto = "Mi pedido 2026-07-18 está listo";
const resultado = texto.match(/(\d{4})-(\d{2})-(\d{2})/);

console.log(resultado[0]); // "2026-07-18"  (la coincidencia completa)
console.log(resultado[1]); // "2026"        (grupo de captura 1)
console.log(resultado[2]); // "07"          (grupo 2)
console.log(resultado.index); // 10          (posición donde empieza)

Sin g, match() devuelve la primera coincidencia con todos sus grupos de captura, más metadatos útiles como index (dónde empieza) e input (la cadena original).

Con flag g: todas las coincidencias, sin grupos

const texto = "gato, pato, rato, dato";
const palabras = texto.match(/\w+ato/g);

console.log(palabras); // ["gato", "pato", "rato", "dato"]

Con g, match() devuelve un array plano con todas las coincidencias completas, pero pierde los grupos de captura y los metadatos. Si necesitas las coincidencias globales y sus grupos, ese es justo el trabajo de matchAll().

El gotcha del null

Cuando no hay ninguna coincidencia, match() devuelve null, no un array vacío:

const resultado = "hola mundo".match(/\d+/);
console.log(resultado); // null

// ❌ Esto lanza "Cannot read properties of null"
// resultado.length

// ✅ Comprueba siempre antes de usar el resultado
const numeros = "hola mundo".match(/\d+/) ?? [];
console.log(numeros.length); // 0

Olvidar este null es uno de los bugs más frecuentes al usar match().

3. String.prototype.matchAll()

cadena.matchAll(regexp)

matchAll() resuelve la limitación de match() con g: devuelve todas las coincidencias con sus grupos de captura completos. Lo hace mediante un iterador, así que normalmente lo consumes con el operador spread o con for...of.

const texto = "Pedidos: 2026-07-18 y 2026-08-02";
const matches = [...texto.matchAll(/(\d{4})-(\d{2})-(\d{2})/g)];

for (const m of matches) {
  console.log(`Fecha completa: ${m[0]}, año: ${m[1]}, mes: ${m[2]}`);
}
// Fecha completa: 2026-07-18, año: 2026, mes: 07
// Fecha completa: 2026-08-02, año: 2026, mes: 08

matchAll() exige el flag g

Si olvidas el flag global, matchAll() lanza un error (a diferencia de match(), que simplemente cambia de comportamiento):

// ❌ TypeError: matchAll must be called with a global RegExp
"texto".matchAll(/\d+/);

// ✅ Correcto
"texto 123".matchAll(/\d+/g);

Esta decisión de diseño es intencional: obliga a que quede explícito en el código que esperas varias coincidencias.

4. match() vs matchAll(): cuál usar

Necesitas… Usa
Saber si hay coincidencia (o extraer la primera) con sus grupos match() sin g
Un array plano de todas las coincidencias (sin grupos) match() con g
Todas las coincidencias con sus grupos de captura e índices matchAll() con g

En la práctica, matchAll() es la opción moderna y recomendada cuando trabajas con varias coincidencias y grupos: es más predecible y no tiene el efecto sorpresa del flag g.

5. Grupos de captura con nombre

Los grupos numerados (m[1], m[2]) son frágiles: si reordenas la regex, se rompe todo. Los grupos con nombre (?<nombre>...) hacen el código mucho más legible y aparecen en la propiedad .groups:

const fecha = "2026-07-18";
const { groups } = fecha.match(/(?<anio>\d{4})-(?<mes>\d{2})-(?<dia>\d{2})/);

console.log(groups.anio); // "2026"
console.log(groups.mes);  // "07"
console.log(groups.dia);  // "18"

Con matchAll() funciona igual y es donde más brilla:

const texto = "IP 192.168.0.1 y 10.0.0.5";
const ips = [...texto.matchAll(/(?<octeto>\d{1,3})\.\d{1,3}\.\d{1,3}\.\d{1,3}/g)];

for (const ip of ips) {
  console.log(`IP ${ip[0]} empieza por ${ip.groups.octeto}`);
}

Puedes probar y depurar estos patrones en vivo con el probador de expresiones regulares antes de llevarlos a tu código.

6. Casos prácticos reales

// Extraer todos los emails de un texto
const texto = "Escribe a [email protected] o a [email protected]";
const emails = texto.match(/[\w.+-]+@[\w-]+\.[\w.-]+/g);
// ["[email protected]", "[email protected]"]

// Extraer hashtags de un comentario
const comentario = "Me encanta #javascript y el #desarrolloweb 🚀";
const hashtags = [...comentario.matchAll(/#(?<tag>\w+)/g)].map((m) => m.groups.tag);
// ["javascript", "desarrolloweb"]

// Sacar todos los números (incluidos decimales)
const factura = "Subtotal 1250.50, IVA 200, Total 1450.50";
const numeros = factura.match(/\d+(\.\d+)?/g);
// ["1250.50", "200", "1450.50"]

// Contar cuántas veces aparece una palabra
const parrafo = "test de test para testear el test";
const veces = [...parrafo.matchAll(/\btest\b/g)].length;
// 3

Para textos largos donde quieras verificar cuántas coincidencias esperas, apóyate en el contador de palabras.

7. match(), test() y exec(): cómo se relacionan

match() y matchAll() viven en el objeto String, pero el objeto RegExp ofrece dos métodos que a veces encajan mejor:

// RegExp.test() → solo quieres saber SÍ o NO (más rápido)
/\d+/.test("hola 123"); // true

// RegExp.exec() con g → itera coincidencia a coincidencia manteniendo lastIndex
const regex = /\d+/g;
let m;
while ((m = regex.exec("a1 b2 c3")) !== null) {
  console.log(m[0], "en índice", m.index);
}

Guía rápida: usa test() cuando solo necesites un booleano, match()/matchAll() cuando quieras extraer los datos, y exec() en bucle solo en casos avanzados donde necesites controlar lastIndex manualmente.

8. Errores comunes con match() y matchAll()

  1. No comprobar el null. match() devuelve null si no hay coincidencia; usa ?? [] o un if antes de acceder al resultado.
  2. Esperar grupos de captura con match(/.../g). Con el flag g, match() los descarta. Si quieres grupos, usa matchAll().
  3. Olvidar el flag g en matchAll(). Lanza un TypeError, no falla en silencio.
  4. Reutilizar una RegExp con g en varios sitios. Un objeto RegExp global mantiene lastIndex entre llamadas de exec()/test() y puede dar resultados inconsistentes; crea la regex donde la uses.
  5. No escapar caracteres especiales. Puntos, paréntesis o corchetes en el patrón deben escaparse (\., \() si los buscas literalmente.

9. Rendimiento y buenas prácticas

  • Si solo necesitas comprobar existencia, test() es más rápido que match() porque no construye el array de resultados.
  • Prefiere matchAll() a match() con g cuando trabajes con grupos: el código queda más claro y evitas el comportamiento sorpresa del flag global.
  • Usa grupos con nombre en cuanto tu regex tenga más de un grupo: tu yo del futuro te lo agradecerá.
  • Compila la expresión regular una sola vez (fuera del bucle) si vas a aplicarla a muchas cadenas.

Con replace(), split(), match() y matchAll() en tu caja de herramientas cubres las cuatro operaciones esenciales sobre cadenas: sustituir, dividir, extraer una y extraer todas. Es prácticamente todo el trabajo con texto que necesitarás en JavaScript.

Conclusión

match() y matchAll() son la pieza que completa el dominio de las cadenas en JavaScript: la parte de extraer. La clave es interiorizar cómo el flag g transforma a match(), comprobar siempre el null y pasarte a matchAll() con grupos con nombre en cuanto la cosa se pone seria.

Para redondear la manipulación de texto en JavaScript:

¿Qué es lo más rebuscado que has tenido que extraer de un texto con una regex? Casi siempre, matchAll() con un grupo con nombre lo resuelve con elegancia.

Compartir

Buscar

Etiquetas

Tutorial Laravel PHP Desarrollo Web JavaScript Buenas Prácticas IA Laravel 13 Seguridad SEO Expresiones Regulares Manipulación de Texto Frontend OpenAI VS Code