Melhores resultados de correspondência com String.prototype.matchAll()

Joe Medley
Joe Medley

O Chrome 73 apresenta o método String.prototype.matchAll(). Ele se comporta de maneira semelhante a match(), mas retorna um iterador com todas as correspondências de expressão regular em uma expressão regular global ou fixa. Isso oferece uma maneira simples de iterar sobre correspondências, especialmente quando você precisa de acesso a grupos de captura.

O que há de errado com match()?

A resposta curta é "nenhum", a menos que você esteja tentando retornar correspondências globais com grupos de captura. Aqui está um quebra-cabeça de programação para você. Considere o seguinte código:

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

Execute isso em um console e observe que ele retorna uma matriz contendo as strings 'test1' e 'test2'. Se eu remover a flag g da expressão regular, o que eu receberei terá todos os meus grupos de captura, mas apenas a primeira correspondência. Esta é a aparência dela:

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

Esta string contém uma segunda possível correspondência que começa com 'test2', mas eu não a tenho. Agora, o quebra-cabeças: como conseguir todos os grupos de captura para cada correspondência? O explicador da proposta String.prototype.matchAll() mostra duas abordagens possíveis. Não vou descrever essas opções porque espero que você não precise delas por muito tempo.

String.prototype.matchAll()

Como seriam os exemplos de explicação com matchAll()? Confira.

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

Há algumas coisas a serem observadas sobre isso. Ao contrário de match(), que retorna uma matriz em uma pesquisa global, matchAll() retorna um iterador que funciona muito bem com loops for...of. O iterador produz uma matriz para cada correspondência, incluindo os grupos de captura com alguns extras. Se você imprimir esses dados no console, eles vão ficar assim:

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

O valor de cada correspondência é uma matriz no mesmo formato retornado por match() para expressões regulares não globais.

Material bônus

Este artigo é principalmente para pessoas que não conhecem ou não são especialistas em expressões regulares. Você pode ter notado que os resultados de match() e matchAll() (para cada iteração) são matrizes com algumas propriedades nomeadas adicionais. Ao preparar este artigo, notei que essas propriedades têm algumas deficiências de documentação no MDN, que foram corrigidas. Confira uma breve descrição.

index
O índice do primeiro resultado na string original. No exemplo acima, test2 começa na posição 5, portanto index tem o valor 5.
input
A string completa em que matchAll() foi executada. No meu exemplo, foi 'test1test2'.
groups
Contém os resultados de todos os grupos de captura nomeados especificados na expressão regular.

Conclusão

Se eu tiver esquecido de algo, deixe um comentário abaixo. Leia mais sobre as mudanças recentes no JavaScript em atualizações anteriores ou no site do V8.