正規表現で探す — test() と match() と matchAll()

あるかどうかだけなら test()、取り出すなら match()、全部取り出すなら matchAll() です。 g フラグを付けたときに戻り値の形が変わること、test() が前回の位置を覚えてしまう罠まで確かめます。

実行して検証済み処理系Node 22.22.3対応ES3難易度●●●○○目安10更新

あるかどうかだけなら test() です。真偽値が返ります。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true false
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ '12' ] null

取り出したいなら match() です。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
見つからない
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ '12' ] [ '12', '34' ]

見つからないときは空配列ではなく nullです。そのまま [0] を読むと落ちます。

使い分け

したいこと 使うもの 見つからないとき
あるか無いか re.test(s) false
最初の1つを取り出す s.match(re) null
全部取り出す [...s.matchAll(re)] 空配列
位置だけ欲しい s.search(re) -1
置き換える s.replace(re, ...) 元のまま

null が返るのは match() だけです。ここが事故の起点になります。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
2 [ 'a1', 'b22' ] [ [ 'a', '1' ], [ 'b', '22' ] ] 0
javascript
try {
[...'a1'.matchAll(/\d/)];
} catch (error) {
console.log(error.name);
}
TypeError

g を付けると戻り値の形が変わる

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
2026 09 08 2026-09-08 0
javascript
const re = /a/g;

console.log(re.test('aa'), re.lastIndex);
console.log(re.test('aa'), re.lastIndex);
console.log(re.test('aa'), re.lastIndex);
true 1 true 2 false 0

見た目は似ていますが中身が違います。

  • g なし … 最初の1つ。[0] が一致した文字列、[1] 以降がキャプチャ
  • g あり … 一致した文字列だけを並べた配列。キャプチャは消える

g を付けると「どこで一致したか」も「括弧の中身」も失われます。

全部を、中身つきで取り出す

matchAll() を使います。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true true
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
a-b ---

一致ごとに、キャプチャも位置も持ったまま取れます。 戻り値はイテレータなので、[...] で配列にしてから使います。

g を忘れると例外になります。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true false
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
true a b a[1]b[2] 08/09/2026

文言は「String.prototype.matchAll called with a non-global RegExp argument」(Node 22.22.3)。処理系によって変わります。

名前を付けて取り出す

(?<名前>…) と書くと、groups から引けます。

番号で数えるより壊れにくくなります。 括弧を1つ足しただけで m[2] が別のものを指す、という事故が起きません。

いちばんの落とし穴:g 付きの test()

同じ文字列を3回調べたのに、3回目だけ false です。

g 付きの正規表現は前回どこまで見たかlastIndex に覚えています。 test() はそこから探し始めるので、呼ぶたびに結果が変わります。

g を外せば起きません。

「あるか無いか」を調べる正規表現に g は要りません。 使い回す正規表現を定数に置いているときほど当たりやすい罠です。

replace() と replaceAll()

特殊文字を打ち消す

. は「任意の1文字」です。そのまま書くと別の意味になります。

文字列から正規表現を作るときは、さらに気をつけてください。

new RegExp() に渡すのは文字列なので、\ を打ち消すのに \\ が要ります。

利用者が入力した文字列を、そのまま正規表現にしないでください。 意図しない一致に加えて、書き方によっては処理が極端に遅くなることがあります。 探すだけなら includes() で足ります。

打ち消しを行う RegExp.escape() は新しい提案で、Node 22.22.3 にはまだありません。

よく使う形

  • ^$全体が一致するかを見る(付けないと一部でも通る)
  • \s+ で連続した空白をまとめる
  • 置き換えに関数を渡せる
  • $1キャプチャを並べ替えられる

まとめ

  • あるか無いかは test()、取り出すなら match()、全部なら matchAll()
  • match() は見つからないと null ?. で守る
  • g を付けると match() の戻り値からキャプチャが消える
  • matchAll()g が必須。位置もキャプチャも残る
  • g 付きの test() は呼ぶたびに結果が変わるlastIndex
  • 名前付きグループを使うと、括弧を足しても壊れない
  • 文字列から作るときは \\ で打ち消す。利用者の入力をそのまま渡さない

正規表現を使わずに済むなら、そのほうが読みやすくなります。 探すだけ・分けるだけの場面は、こちらにまとめてあります。 → 文字列を探す・分ける・置き換える

この記事の根拠

  1. RegExp (Regular Expression) Objects — ECMAScript® 2026 Language Specificationtc39.es
  2. String.prototype.matchAll — ECMAScript® 2026 Language Specificationtc39.es
  3. 正規表現 — MDNdeveloper.mozilla.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)