正規表現テストガイド:一致とグループを目で確認する
正規表現が思いどおりに動かないときは、資料を読むより実行結果を見たほうが速いです。パターンと実データを並べれば、どこに一致し、どこを取りこぼし、各グループに何が入るかが一目で分かります。
先に試す価値がある場面
ログから IP、注文番号、タイムスタンプなど決まった形のデータを抜き出す作業は、まず一度でうまくいきません。サンプル上で先に通しておくほうが、スクリプトに書いて何度も再実行するより速いです。フォーム検証も同じで、メールアドレスや電話番号の規則は、末尾の空白や全角文字、先頭の 0 といった境界を実データで試して初めて見えてきます。
他人のコードを引き継いだときも同じです。コメントのないパターンをテスト画面に貼れば、何に一致し、どんなグループを持つのかを頭の中で追うより確実に分かります。置換の前に対象が何件あるか確認しておけば、ファイル全体を壊す事故も防げます。
つまずかないための確認事項:方言・フラグ・境界
まず方言を確認してください。ここはブラウザの JavaScript エンジンで、PCRE や Python、Java とは細部が違います。JS の \d は ASCII の数字だけ、\w は ASCII の英数字とアンダースコアだけに一致します(u フラグでも変わりません)。名前付きグループの書き方やバックトラックの挙動も独自です。ここで通っても grep -P で通るとは限りません。
次にフラグです。g は全体検索で、付けないと最初の 1 件しか返りません。i は大文字小文字の無視、m は ^ と $ を各行の先頭と末尾に一致させ、s はドットを改行にも一致させます。最も多い落とし穴は m の付け忘れです。複数行のテキストでは、m がないと 1 行目しか ^ に一致しません。
- サンプルは 2 組用意します。一致すべき文字列と、一致してはいけない文字列です。前者だけでは半分しか検証できません
- 値を取り出さないグループは (?:...) にしてください。グループが多いと結果欄が読みにくくなります
- 貪欲な .* は、怠惰な .*? かより限定的な文字クラスに置き換えると、想定外の一致が減ります
- ^ と $ で全体を固定するかどうかを先に決めてください。決めないと部分一致が通ってしまいます
限界:一致することと、適切な道具であることは別
最大のリスクは壊滅的なバックトラックです。(a+)+$ のような入れ子の量指定子は、長い文字列が「もう少しで一致しそうで一致しない」ときに指数関数的に遅くなります。ブラウザの正規表現エンジンにはタイムアウトがないため、タブが固まり、閉じるしかなくなります。このツールの 5000 件上限は結果の量を抑えるもので、バックトラック自体は防げません。
また、正規表現は入れ子構造の解析に向きません。HTML、JSON、XML にはそれぞれパーサーがあり、タグをパターンで追うと入れ子やコメントで破綻します。メールアドレスや URL の完全な仕様も 1 つの正規表現では覆えません。実務では緩めの規則で受けて、確認メールで検証するほうが安全です。数 MB を超えるテキストは、分割してから一致させてください。
よくある質問
同じ正規表現がツールでは動くのに、コードでは動かないのはなぜですか?
3 点を確認してください。方言が同じか(ここは JS エンジンで、Python、PHP、Java とは書き方が違います)、フラグが同じか(特に g と m)、そして文字列が余分にエスケープされていないか。JSON や YAML からパターンを読むと、バックスラッシュが二重になり、\d が数字ではなく「バックスラッシュと d」を意味してしまうことがよくあります。
貪欲と怠惰はどう違いますか?
貪欲な .* はできるだけ後ろまで取り、怠惰な .*? はできるだけ少なく取ります。<b>甲</b><b>乙</b> に対して <b>.*</b> は最後の閉じタグまで一気に飲み込み、<b>.*?</b> なら 2 組に分かれます。既定は貪欲なので、最短で止めたいときに ? を付けます。
入れ子の量指定子は必ず固まりますか?
必ずではありません。入力次第です。(a+)+$ は a が続くだけの文字列にはほぼ即座に一致し、「長い a の列のあとに b が 1 つ」という惜しい入力で爆発します。だからこそ、手元のきれいなデータではなく、一致しそうで一致しない例で試す必要があります。
関連ツール:Regex Tester