【実務・中級編】 matchAll() による正規表現の全一致取得 – JavaScript実践ガイド

正規表現の「全一致」で消耗するな。`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: (?\d+), Name: (?\w+)/g;

// 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]` とインデックスでアクセスするのはやめよう。コードの意図が全く伝わらない。`(?…)` という名前付きキャプチャグループを使えば、`match.groups.name` で直感的にアクセスできる。後で修正する同僚のためにも、可読性は正義だ。

—

最後に:綺麗なコードは「道具の理解」から

「動けばいい」という考え方は、ジュニアまでだ。僕らのようなシニア層は、「いかにJavaScriptの標準仕様が意図している『理想的な使い方』に寄せるか」を重視する。

`matchAll()`は、正規表現という古くからある強力な道具を、モダンなイテレータプロトコルと融合させた素晴らしいメソッドだ。これを使いこなすだけで、君の書くコードから「意味不明なループ」や「管理不能なインデックス」が一つ消える。

次に正規表現を書くときは、迷わず`matchAll()`を手に取ってくれ。君のコードがより美しくなることを期待しているよ。

コメント

タイトルとURLをコピーしました