正規表現の「全一致」で消耗するな。`matchAll()` でスマートに解決する現場の最適解
現場でコードレビューをしていると、今でもたまに見かけるんだ。「`g`フラグをつけた`match()`メソッド」で苦労しているコードをね。
「マッチした文字列のリストは取れたけど、キャプチャグループの中身も一緒に取りたいんだよね……」という状況で、わざわざ`while`ループと`exec()`を組み合わせて、無限ループに怯えながらインデックスを管理する。あれ、正直言って「負け」のコードだよ。
現代のJavaScript開発において、正規表現の全一致を取得するなら、間違いなく`matchAll()`を使うのが正解だ。今日は、なぜこれが「現場の最適解」なのか、裏側の仕組みと合わせて解説していくよ。
—
なぜ `match()` ではなく `matchAll()` なのか?
まずは君が明日から卒業すべき「古い戦い方」を思い出してほしい。
// 【旧世代】 execを使った泥臭いループ
const regex = /(.?)<\/span>/g;
const str = ‘JSTS‘;
let match;
// ループのたびにlastIndexを制御しないと無限ループの危険性がある
while ((match = regex.exec(str)) !== null) {
console.log(match[1]); // キャプチャグループは取れるが、コードが冗長すぎる
}
この書き方は、`lastIndex`という「正規表現オブジェクトが保持する内部状態」を人間が管理しなきゃいけない。これがバグの温床になるんだ。
一方、`matchAll()`は「イテレータ」を返す。これによって、コードは劇的にクリーンになる。
`matchAll()` 実践:イテレータの恩恵をフル活用する
`matchAll()`の最大の利点は、「各マッチごとに、フルセットのキャプチャグループ情報を持つ配列が降ってくる」という点にある。
以下のコードを見てほしい。実務でよくある、HTMLタグから情報を抜き出すケースだ。
const htmlContent = ‘ID: 101, Name: Alice; ID: 102, Name: Bob;’;
// 名前付きキャプチャグループで可読性を上げるのがプロの作法
const regex = /ID: (?
// matchAllはイテレータを返すので、スプレッド構文やfor…ofで回せる
const matches = […htmlContent.matchAll(regex)];
for (const match of matches) {
// match[0] はマッチした文字列全体
// match.groups は名前付きキャプチャグループのオブジェクト
const { id, name } = match.groups;
console.log(`ID: ${id} のユーザーは ${name} さんです。`);
}
ここが技術のポイント:ブラウザはどう動いているか?
`matchAll()`が返しているのは、配列そのものではなく「イテレータ」だ。つまり、メモリ上では全ての検索結果を一度に生成するのではなく、`next()`を呼ばれるたびに正規表現のエンジンがマッチを計算する。
大量の文字列を扱う際、配列をメモリに展開せずに逐次処理できるのはパフォーマンス上も非常に有利なんだ。ブラウザのエンジン(V8など)にとっても、イテレータベースの処理は最適化が効きやすい。
—
実務で「これだけは守れ」という3つのTips
現場で`matchAll()`を採用する際、気をつけておきたいポイントを伝授しておく。
1. `g`フラグを忘れるな
`matchAll()`はグローバルマッチ(`g`フラグ)が必須だ。これがないと`TypeError`を投げてくる。「なぜ動かないんだ?」と悩んだら、まず正規表現の末尾を確認すること。
2. イテレータの再利用はできない
一度`for…of`で回しきったイテレータは空になる。何度も同じ結果を使いたいなら、一度スプレッド構文`[…matches]`で配列に変換してしまうのが現実的な現場判断だ。
3. 名前付きキャプチャグループを活用せよ
`match[1]`, `match[2]` とインデックスでアクセスするのはやめよう。コードの意図が全く伝わらない。`(?
—
最後に:綺麗なコードは「道具の理解」から
「動けばいい」という考え方は、ジュニアまでだ。僕らのようなシニア層は、「いかにJavaScriptの標準仕様が意図している『理想的な使い方』に寄せるか」を重視する。
`matchAll()`は、正規表現という古くからある強力な道具を、モダンなイテレータプロトコルと融合させた素晴らしいメソッドだ。これを使いこなすだけで、君の書くコードから「意味不明なループ」や「管理不能なインデックス」が一つ消える。
次に正規表現を書くときは、迷わず`matchAll()`を手に取ってくれ。君のコードがより美しくなることを期待しているよ。

コメント