正規表現チートシート

JavaScript 方言向けの検索可能な正規表現チートシート。文字クラス、ブラケット集合、量指定子、アンカー、先読み・後読み、グループ、フラグを例付きで掲載。

例付きの正規表現構文 41 項目。 トークン・説明・例を横断して絞り込み、必要な構文をそのままコピーできます。ブラウザと Node.js で使われる JavaScript(ECMAScript)方言に準拠しています。

正規表現を自信を持って読み書きする

これはチュートリアルではなく構文表です

正規表現はもともと情報密度が高い記法です。^(?:\d{1,3}\.){3}\d{1,3}$ という 30 文字ほどのパターンに IPv4 バリデータ一式が収まっています。自分で書いたときは快適ですが、他人が書いたものを読むときは苦痛です。難しさの大半は概念ではなく、語彙が多く、簡潔で、中途半端に覚えやすいという点にあります。

このページはその語彙の逆引き表で、実際にパターンを組み立てる順序で整理してあります。1 文字に一致する記法、独自の文字集合の定義、「繰り返し」の表現、一致位置のアンカー、グループ化と選択、そしてエンジンの挙動を変えるフラグです。フィルタはトークン・説明・例を同時に検索するため、「最短」「boundary」「lookbehind」などを入力すれば、うろ覚えの行にすぐ辿り着けます。

どの方言に準拠しているか

正規表現は単一の言語ではありません。grep、PCRE、Python、Java、Go の RE2、JavaScript は共通の中核を持ちながら、細部で食い違います。ここに掲載しているものはすべて ECMAScript が定める JavaScript 方言を対象としています。ブラウザ、Node.js、そして大半のフロントエンドツールで動くのがこの方言だからです。

特に注意したい差異が三つあります。第一に、後読み (?<=...)(?<!...) は現代の JavaScript エンジンでは利用できますが、Go の RE2 や古い Safari では使えないため、これに依存するパターンはどこでも移植できるわけではありません。第二に、JavaScript には x(拡張)フラグがないため、Python のようにパターンを複数行に分けてコメントを付けることはできません。長いパターンは通常、文字列断片を連結して組み立てます。第三に、JavaScript の \d\w は既定で ASCII のみを対象とするため、u フラグ付きの \p{L} のような Unicode プロパティエスケープに切り替えない限り、\w はアクセント付き文字や CJK 文字に一致しません。

保守できるパターンを書くために

二つの習慣が、正規表現にまつわる苦労のほとんどを防いでくれます。一つ目は、意図してアンカーを付けることです。アンカーのないパターンは文字列内のどこかに一致を探します。テキストを走査する場合はそれで正しいのですが、検証する場合はほぼ常に不適切です。^$ を加えると「日付らしきものを含む」が「日付そのものである」に変わります。この違いが、検証系バグの相当な割合の背後にあります。

二つ目は、貪欲なワイルドカードよりも最短一致と否定文字クラスを選ぶことです。典型的な失敗は HTML 風のテキストに対する <.+> で、+ が貪欲なため行末近くの最後の > まで飲み込んでしまいます。<.+?>、さらに望ましくは <[^>]+> と書けば、タグ 1 個だけに一致します。否定クラス版はバックトラックが不要なぶん、速度面でも明確に有利です。

最後に、破滅的バックトラッキングに注意してください。(a+)+b のように量指定子を入れ子にすると、エンジンは「一致しない」と結論づける前に指数関数的な数の分割を試すことがあります。そのパターンがユーザー入力に触れる場合、検証処理がそのままサービス拒否の攻撃面になります。量指定子付きのグループがさらに量指定子を含んでいるなら書き直しましょう。多くの場合、文字クラス 1 つと量指定子 1 つで同じ仕事を線形時間でこなせます。そしてパターンが一、二行を超えて伸びてきたときは、正しい道具は正規表現ではなく本物のパーサーである、というのが正直な答えであることが多いのです。

自社実装です。構文表は JavaScript(ECMAScript)の正規表現方言を対象とし、すべての処理はブラウザ内で完結します。

よくある質問

これらのトークンはどの正規表現方言を対象にしていますか?
JavaScript(ECMAScript)方言です。ブラウザ、Node.js、大半のフロントエンドツールで動作する方言にあたります。基本構文は PCRE、Python、Java と共通なので大部分はそのまま移植できますが、他のエンジンを対象にする場合は後読みと Unicode プロパティエスケープの対応状況を個別に確認してください。
なぜパターンが想定より多くの文字に一致するのですか?
ほぼ必ず量指定子が貪欲だからです。* と + は可能な限り多くを取り込み、後続の照合が失敗して初めて文字を戻します。.+? のように ? を付けて最短一致にするか、[^>]+ のような否定文字クラスに置き換えてください。後者はより正確で、速度も優れています。
キャプチャグループと非キャプチャグループの違いは何ですか?
(abc) は一致内容を保存し、後から \1 で参照したり結果配列から読み出したりできます。(?:abc) は量指定子や選択を適用するためにトークンをまとめるだけで、何も保存しません。グループ化だけが必要なときは非キャプチャ形式を使うと、結果のインデックスが安定し、オーバーヘッドもわずかに減ります。
なぜ \w はアクセント付き文字や漢字に一致しないのですか?
JavaScript の \w は [A-Za-z0-9_] と定義されており、意図的に ASCII のみを対象としています。任意の文字体系の文字に一致させるには、u フラグとともに Unicode プロパティエスケープを使ってください。/\p{L}+/u ならラテン、キリル、ギリシャ、漢字、仮名などあらゆる文字に一致します。
正規表現がセキュリティ上のリスクになることはありますか?
あります。(a+)+b のような入れ子の量指定子は破滅的バックトラッキングを引き起こし、失敗と判定するまでに指数関数的な数の可能性を探索することがあります。そのパターンをユーザー入力に適用すると、短い細工文字列だけでプロセスを停止させられます。入れ子の量指定子は可能な限り単一の文字クラスへ書き直してください。
HTML や JSON の解析に正規表現を使ってもよいですか?
使うべきではありません。どちらも再帰的な形式であり、正規表現は任意の深さの入れ子を表現できません。HTML には DOMParser、JSON には JSON.parse という本物のパーサーを使ってください。正規表現が適しているのは、平坦なテキストの走査、単純なフィールド形式の検証、そして限定的な検索置換です。