String.prototype.matchAll()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.
試してみましょう
構文
matchAll(regexp)
引数
regexp
-
正規表現オブジェクト、または
Symbol.matchAll
を持つ任意のオブジェクトです。regexp
がRegExp
以外のオブジェクトであった場合、暗黙的にRegExp
への変換がnew RegExp(regexp, 'g')
を使用して行われます。regexp
が正規表現である場合、グローバルフラグ (g
) が設定されます。そうでなければTypeError
が発生します。
返値
一致したものの反復可能なイテレーターオブジェクト(再起動不可能なもの)、または一致するものがなければ空のイテレーターです。イテレーターが生成するそれぞれの値は、RegExp.prototype.exec()
の返値と同じ形です。
例外
解説
String.prototype.matchAll
の実装自体は、正規表現がグローバルであるという余分な入力検証を除けば)非常にシンプルで、引数の文字列を最初の引数として Symbol.matchAll
メソッドを呼び出すだけです。実際の実装は RegExp.prototype[Symbol.matchAll]()
から来ています。
例
Regexp.prototype.exec() と matchAll()
matchAll()
が JavaScript に追加される前は、 regexp.exec(および /g
フラグ付きの正規表現)をループの中で呼び出すことですべての一致結果を取得することができました。
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
let match;
while ((match = regexp.exec(str)) !== null) {
console.log(
`Found ${match[0]} start=${match.index} end=${regexp.lastIndex}.`,
);
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.
matchAll()
が使えるようになったことで、 while
によるループと、g
付きの exec
を避けることができます。代わりにイテレーターが取得できるので、for...of
、配列スプレッド、Array.from()
構造と効率よく組み合わせることができます。
const regexp = /foo[a-z]*/g;
const str = "table football, foosball";
const matches = str.matchAll(regexp);
for (const match of matches) {
console.log(
`Found ${match[0]} start=${match.index} end=${
match.index + match[0].length
}.`,
);
}
// Found football start=6 end=14.
// Found foosball start=16 end=24.
// 一致したイテレーターは for...of の反復処理の後で利用不可になる
// 新しいイテレーターを作成するために matchAll を再度呼び出す
Array.from(str.matchAll(regexp), (m) => m[0]);
// [ "football", "foosball" ]
matchAll
は、グローバル (g
) フラグがない場合は例外が発生します。
const regexp = /[a-c]/;
const str = "abc";
str.matchAll(regexp);
// TypeError
matchAll
では内部的に regexp
の複製を作成します。そのため regexp.exec()
とは違って文字列をスキャンした際に lastIndex
が変わることはありません。
const regexp = /[a-c]/g;
regexp.lastIndex = 1;
const str = "abc";
Array.from(str.matchAll(regexp), (m) => `${regexp.lastIndex} ${m[0]}`);
// [ "1 b", "1 c" ]
しかし、これは regexp.exec()
をループ内で使うのとは異なり、正規表現を進めたり戻したりするために lastIndex
を変更することができないことを意味します。
キャプチャリンググループへのより良いアクセス(String.prototype.match() との比較)
matchAll
はキャプチャグループへのよりよいアクセスを実現します。
match()
では、グローバル g
フラグを使用するとキャプチャグループが無視されてしまいます。
const regexp = /t(e)(st(\d?))/g;
const str = "test1test2";
str.match(regexp); // ['test1', 'test2']
matchAll
を使えば簡単にキャプチャグループにアクセスできます。
const array = [...str.matchAll(regexp)];
array[0];
// ['test1', 'e', 'st1', '1', index: 0, input: 'test1test2', length: 4]
array[1];
// ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', length: 4]
matchAll() を RegExp ではない [Symbol.matchAll]()
を実装しているオブジェクトで使用
オブジェクトに Symbol.matchAll
メソッドがあれば、それをカスタムマッチャーとして使うことができます。Symbol.matchAll
の返値は matchAll()
の返値となる。
const str = "Hmm, this is interesting.";
str.matchAll({
[Symbol.matchAll](str) {
return [["Yes, it's interesting."]];
},
}); // [["Yes, it's interesting."]] を返す
仕様書
Specification |
---|
ECMAScript Language Specification # sec-string.prototype.matchall |
ブラウザーの互換性
BCD tables only load in the browser