Mejor coincidencia de resultados con String.prototype.matchAll()

Joe Medley
Joe Medley

Chrome 73 presenta el método String.prototype.matchAll(). Se comporta de manera similar a match(), pero muestra un iterador con todas las coincidencias de expresiones regulares en una expresión regular global o fija. Esto ofrece una manera sencilla de iterar en las coincidencias, en especial cuando necesitas acceso para capturar grupos.

¿Cuál es el problema con match()?

La respuesta corta no es nada, a menos que intentes mostrar coincidencias globales con grupos de captura. Aquí tienes un acertijo de programación para ti. Considera el siguiente código:

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const results = string.match(regex);
console.log(results);
// → ['test1', 'test2']

Ejecuta esto en una consola y observa que muestra un array que contiene las cadenas 'test1' y 'test2'. Si quito la marca g de la expresión regular, lo que obtengo tendrá todos mis grupos de captura, pero solo obtengo la primera coincidencia. El aspecto resultante será el siguiente:

['test1', 'e', 'st1', '2', index: 0, input: 'test1test2', groups: undefined]

Esta cadena contiene una segunda coincidencia posible que comienza con 'test2', pero no la tengo. Ahora, está el acertijo: ¿cómo obtengo todos los grupos de captura para cada partida? La explicación de la propuesta String.prototype.matchAll() muestra dos enfoques posibles. No los describiré porque con suerte no los necesitarás mucho más tiempo.

String.prototype.matchAll()

¿Cómo se verían los ejemplos de explicación con matchAll()? ¡Descúbrelo!

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';
const matches = string.matchAll(regex);
for (const match of matches) {
  console.log(match);
}

Debes tener en cuenta algunos aspectos al respecto. A diferencia de match(), que muestra un array en una búsqueda global, matchAll() muestra un iterador que funciona a la perfección con bucles for...of. El iterador produce un array para cada coincidencia, incluidos los grupos de captura con algunos extras. Si los imprimes en la consola, se verán de la siguiente manera:

['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', groups: undefined]
['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined]

Tal vez notes que el valor de cada coincidencia es un array en exactamente el mismo formato que muestra match() para las expresiones regulares no globales.

Material adicional

Esto es principalmente para personas que son nuevas con las expresiones regulares o que no son expertos en ellas. Es posible que hayas notado que los resultados de match() y matchAll() (para cada iteración) son arrays con algunas propiedades adicionales con nombre. Mientras preparaba este artículo, noté que estas propiedades tienen algunas deficiencias de documentación en MDN (que solucioné). Esta es una descripción breve.

index
Es el índice del primer resultado en la string original. En el ejemplo anterior, test2 comienza en la posición 5, por lo que index tiene el valor 5.
input
La cadena completa en la que se ejecutó matchAll(). En mi ejemplo, era 'test1test2'.
groups
Contiene los resultados de los grupos de captura con nombre especificados en tu expresión regular.

Conclusión

Si me perdí algo, déjalo en los comentarios. Puedes obtener más información sobre los cambios recientes en JavaScript en las actualizaciones anteriores o en el sitio web de V8.