What are the differences between String.prototype.match and String.prototype.matchAll methods?

Asked

Viewed 99 times

6

Historically, Javascript relies on the method String.prototype.match to perform, for example, string searches through a pattern via regular expression.

However, starting with Ecmascript 2020, strings also have the method String.prototype.matchAll.

  • What prompted the introduction of the matchAll?
  • What are the differences and, in general, how should I choose one in relation to the other?

1 answer

7


One difference is that match returns an array and matchAll returns an iterator, but there are several other details to consider.

When the regex doesn’t have the flag g, match returns an array containing only the first occurrence, plus some related information (such as capture groups). But when you have the flag g, the result contains only the pouch, without further information:

let s = 'a1 b2 c3 d4';

console.log('---match---');
// sem flag g, pega somente a primeira ocorrência, com informações adicionais
let result = s.match(/[a-z](\d)/);
for (let i in result) console.log(`${i}=${result[i]}`);

console.log('---matchAll---');
// com flag g, pega todas as ocorrências, sem informações adicionais
result = s.match(/[a-z](\d)/g);
for (let i in result) console.log(`${i}=${result[i]}`);

The regex is [a-z](\d) (a letter followed by a number, the number being in parentheses, which forms a capture group).

Without the flag g, the returned array has:

  • in first position, the first occurrence (a1)
  • in the other positions, the capture groups (in this case, we only have one group, containing the digit 1)
  • the property index containing the index where the match was found (a1 is at the zero index of the string)
  • the property input containing a copy of the entire string
  • the property groups, which contains only the appointed groups (so the group containing the digit is not there).

But if we use the flag g, the array contains only the snippets you have given match (only a1, b2, etc), without the additional information (no groups, index, etc.).


Before matchAll, the only way to get the additional information for all occurrences was by using exec:

let s = 'a1 b2 c3 d4';
let r = /[a-z](\d)/g;
let match;
while (match = r.exec(s)) {
    console.log('----');
    for (let i in match) console.log(`${i}=${match[i]}`);
}

Note that now every call from exec returns an array containing the match and the additional information.

But with matchAll it’s a little simpler to do the same thing:

let s = 'a1 b2 c3 d4';
for (const match of s.matchAll(/[a-z](\d)/g)) {
    console.log('----');
    for (let i in match) console.log(`${i}=${match[i]}`);
}

And how matchAll returns an iterator, you can use it with for..of (as in the example above), with spread to create an array with the results ([...s.matchAll(/[a-z](\d)/g)]), etc..


One detail is that with matchAll, the regex must have the flag g, otherwise will give error (and a curiosity is that if you use exec without the flag g, he gets into loop infinite, since exec search from the lastIndex, but without the flag g this value is always zero, so in this case she will always find a match).

By the way, this is another detail: exec updates the lastIndex from regex, then each call looks from this position. But matchAll does not touch the lastIndex:

let s = 'a1 b2 c3 d4';
let r = /[a-z](\d)/g;
let match;
while (match = r.exec(s)) {
    console.log(r.lastIndex); // o índice vai sendo atualizado conforme encontra os matches
}

let r2 = /[a-z](\d)/g;
for (const m of s.matchAll(r2)) {
    console.log(r2.lastIndex); // não muda, é sempre zero
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.