無料正規表現チートシート
正規表現のインタラクティブなリファレンスガイド。
パターンをテスト
使い方
- パターンカテゴリーを閲覧するか、検索バーを使用して特定のパターンを見つけます。
- 正規表現を「パターンをテスト」フィールドに入力し、サンプルテキストを「テストテキスト」に入力します。
- フラグ(グローバル、大文字小文字を区別しない、マルチライン)を切り替えて、瞬時に強調表示された一致を確認します。
よくある質問
正規表現とは?
正規表現(regexまたはregexp)は、テキストを検索、取得、置換するために使用されるパターンです。特殊な文字と構文を使用して、見つける文字列を定義します。
フラグの目的は?
グローバル(g)はすべての一致を検索します。大文字小文字を区別しない(i)は文字の大文字小文字を無視します。マルチライン(m)は、^と$を文字列の境界ではなく行の境界に一致させます。
このチートシートをコードで使用できますか?
はい!パターンをテストして動作を確認したら、正規表現パターンをJavaScript、Python、その他の言語のコードに直接コピーします。
パターン言語の小史
正規表現は理論計算機科学の一片として生まれました。Stephen Kleene は 1956 年のニューラルネットワークに関する論文で "正則集合" を定義し、Ken Thompson は 1968 年に grep によって Unix に組み込みました。Henry Spencer のオープンソース正規表現ライブラリ(1980 年代半ば)は、その後の多くの実装の基礎になりました。Larry Wall は Perl で構文を大幅に拡張し、彼の "Perl 互換正規表現"(PCRE)は多くの現代的な言語が従う事実上の標準となりました。今日では密接に関連しながらも微妙に異なるいくつかの正規表現の方言が存在し、あるエンジンで動くパターンが別のエンジンで同じように動くとは限りません。
あなたのパターンが動くエンジン
同じ構文でもエンジンによって異なる意味になることがあります。主な系統:
- POSIX BRE(基本正規表現)、
grepの既定モードやsedで使われます。多くのメタ文字はバックスラッシュでエスケープが必要です:(、)、{、}、+、?、|はエスケープしなければリテラル扱いです。 - POSIX ERE(拡張正規表現)、
egrepやawkで使われます。上記のメタ文字はエスケープなしで動作します。 - PCRE(Perl 互換正規表現)、ERE に先読み・後読み、原子グループ、名前付きキャプチャと後方参照を加えたものです。PHP や多くの現代的な言語で使われています。Perl 由来の略記クラス
\d、\w、\sは PCRE、JavaScript、.NET、Java、Python に共通しています。 - JavaScript RegExp、PCRE に近いものの注目すべき違いがあります。ES2018 で後読み、名前付きキャプチャグループ、
sdotall フラグ、uフラグによる Unicode プロパティエスケープが追加されました。集合表記用のvフラグは ES2024 で登場しました。 - Python
reと Pythonregex、reは標準ライブラリにあります。サードパーティのregexモジュールは Unicode 対応機能、可変幅の後読み、その他の PCRE 風の拡張を追加します。 - RE2(Google のライブラリ、Go で使用)、線形時間を保証しますが、後方参照や先読み・後読みはサポートしません。トレードオフは、予測可能な性能と機能の少なさです。
このチートシートのインタラクティブテスターは JavaScript で動作するため、パターンはブラウザの JS エンジンで評価されます。ここで動くパターンが Python や PHP で異なる挙動を示すことがあります。違いの多くは基本構文ではなく高度な機能(後読み、Unicode プロパティエスケープ、後方参照)にあります。
中核となる構成要素
ほとんどすべての正規表現パターンは、次の要素から組み立てられています。
- リテラル、それ自身にマッチします。
catは部分文字列 "cat" にマッチします。 - アンカー、
^(文字列または行の先頭)、$(末尾)、\b(単語境界)、\B(非単語境界)。 - 文字クラス、
[abc]は a、b、c のいずれかにマッチします。[^abc]は否定。[a-z]は範囲。略記:\d(数字)、\w(単語文字: 文字、数字、アンダースコア)、\s(空白)、大文字版は否定(\D、\W、\S)。 - 量指定子、
?(0 か 1)、*(0 以上)、+(1 以上)、{n}、{n,}、{n,m}。既定では貪欲(できるだけ多くマッチ)。?を付けると lazy になります:*?、+?、??。 - グループ、
(...)キャプチャあり、(?:...)キャプチャなし、(?<name>...)名前付き(PCRE、JS、Python)。 - 選択、
cat|dogはどちらか一方にマッチします。 - 先読みと後読み、
(?=...)肯定先読み、(?!...)否定先読み、(?<=...)肯定後読み、(?<!...)否定後読み。文字を消費せずにマッチします。 - 後方参照、
\1、\2(番号付き)、\k<name>(名前付き)。対応するキャプチャがマッチした同じテキストにマッチします。 - フラグ、
g(グローバル)、i(大文字小文字を区別しない)、m(複数行:^と$が行境界にマッチ)、s(dotall:.が改行にもマッチ)、u(Unicode)、y(JS の sticky)。
覚えておく価値のあるパターン
覚えておくと役立つほど頻繁に出てくるパターンがいくつかあります。
| 用途 | パターン |
|---|---|
| メールアドレス(基本) | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ |
| URL | https?://[^\s]+ |
| 米国の電話番号 | \(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4} |
| ISO 日付(YYYY-MM-DD) | \d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) |
| IPv4 アドレス(オクテット検証なし) | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b |
| 16 進カラー | ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ |
| 行頭・行末の空白 | ^\s+|\s+$ |
| 連続する複数のスペース | \s{2,} |
メール用正規表現に関する注意: RFC 5322 に完全準拠したメール検証には 6,000 文字のモンスター正規表現が必要です。上の単純な形は実際のメールアドレスの 99% を受け入れ、正当なものを拒否しません。本番では、構文を完璧に検証しようとするより、確認メールを送る方が確実です。
貪欲と lazy: よくある落とし穴
既定では、量指定子は貪欲です。全体のパターンがマッチできる範囲で、できるだけ多くマッチします。したがって <.+> を <a>text</a> に適用すると <a> だけでなく全体にマッチします。.+ がつかめるだけつかむからです。最小のマッチを得るには、量指定子に ? を付けます: <.+?> は <a> と </a> をそれぞれ別々にマッチさせます。貪欲か lazy かの選択は、"なぜ正規表現が期待どおりにマッチしないのか" という種類のバグで最もよくある原因の一つです。
壊滅的バックトラックと ReDoS
一部の正規表現パターンは特定の入力で失敗するのに指数時間がかかることがあり、これは ReDoS(Regular Expression Denial of Service)というサービス拒否の脆弱性の一種です。古典的な原因は (a+)+ や (a|aa)+ のような入れ子の量指定子を、長い a の列の後に一致しない文字を続けた入力に適用することです。エンジンは諦める前に文字列を分割するあらゆる方法を試し、その方法の数は指数的に増えます。
実例: Cloudflare の 2019 年の障害は、WAF ルールに配置された正規表現が特定の入力で壊滅的にバックトラックしたことで引き起こされました。Stack Overflow も 2016 年 7 月に同様の事件を経験しました。trim 用の正規表現(^[\s]+|[\s]+$)が、約 20,000 文字の連続した空白を含む単一コメントで指数的バックトラックに陥り、サイトは 34 分間ダウンしました。防御的な習慣: 入れ子の量指定子を避ける、サポートされている場合は原子グループ((?>...))を優先する、信頼できない入力には RE2 や線形時間エンジンの使用を検討してください。
言語ごとに知っておく価値のある癖
- JavaScript: 文字列リテラルではバックスラッシュは二重エスケープが必要ですが(
"\\d")、正規表現リテラルでは不要です(/\d/)。可能なときは正規表現リテラル形式を使ってください。 - Python: バックスラッシュ問題を避けるため、生文字列(
r"\d+")を使ってください。reモジュールは標準ライブラリ、PyPI のregexは追加機能を提供します。 - Java: バックスラッシュは四重エスケープが必要です(
\dに対して"\\\\d")。Java の文字列リテラルが\をエスケープとして使い、その後正規表現コンパイラが\\dを見るためです。 - Bash:
[[ string =~ pattern ]]での正規表現照合は POSIX ERE を使います。クォートの規則は厄介なので、man bashを参照してください。 - Go: RE2 を使うため、後方参照と先読み・後読みは使えません。代償として線形時間が保証されます。
正規表現を使うべきでない場面
Jamie Zawinski の有名な 1997 年の一言: "問題に直面したとき、ある人は『そうだ、正規表現を使おう』と思う。今や彼らには問題が二つある。"
- HTML や XML を正規表現で解析しない。 本物のパーサを使ってください(ブラウザの DOMParser、Python の BeautifulSoup、Java の jsoup など)。HTML の入れ子構造は、正規表現が綺麗に表現できる範囲を根本的に超えています。
- JSON を正規表現で解析しない。 JSON.parse や標準ライブラリの JSON パーサを使ってください。
- 正規表現でメールを厳密に検証しない。 確認メールを送ってください。それが唯一の信頼できる検証です。
- CSV パーサを正規表現で書かない。 引用符付きフィールドに含まれるカンマ、エスケープされた引用符、複数行の値は、正規表現が綺麗に扱える範囲をすぐ超えます。
- 釣り合う括弧をマッチさせようとしない。 標準の正規表現にはできません(これは文脈自由言語です)。一部の PCRE エンジンには再帰機能があってごまかせますが、本物のパーサを使う方が綺麗です。
よくある間違い
- 特殊文字のエスケープを忘れる。
.、*、?、+、(、)、[、]、{、}、\、^、$、|、/はすべて特殊な意味を持ちます。リテラルとしてマッチさせるには、バックスラッシュを前に付けてください。 - 貪欲な量指定子が多く消費しすぎる。 最小のマッチが欲しいときは
?を付けて lazy にしてください。 - グローバルフラグを忘れて、最初の一致しか表示されない理由を悩む。 JavaScript の
String.prototype.match()はgフラグなしでは最初の一致しか返しません。 - 長い入力での壊滅的バックトラック。
(a+)+のような入れ子の量指定子は特定の入力で停止することがあります。境界ケースでテストしてください。 - 同じ正規表現がすべての言語で同じように動くと仮定する。 後読み、Unicode エスケープ、文字クラスの略記はすべて異なります。
- メールを厳格に検証しようとする。 技術的に正しい RFC 5322 の正規表現は保守不能です。単純な正規表現と登録時の確認メールが現実的なパターンです。
- HTML、JSON、CSV に正規表現を使う。 適切なパーサを使ってください。最初に節約した時間は、後でバグで失うことになります。
その他のよくある質問
ここでは動くのに、自分のコードで失敗するのはなぜ?
最もよくある原因はエンジンの違いです。JavaScript の RegExp は PCRE がサポートする一部の機能をサポートしません(逆もまた然り)。よくある落とし穴: 後読みは JS には遅れて追加され(ES2018)、名前付きグループの構文は微妙に異なり、Unicode プロパティエスケープは u フラグが必要で、[[:alpha:]] のような POSIX 文字クラスは JS にはほぼありません。デプロイ先のエンジンでテストしてください。
複数行にまたがってマッチする "グローバル" な方法はある?
二つのフラグが連動します。m(複数行)フラグは ^ と $ を文字列全体ではなく各行の先頭・末尾にマッチさせます。s(dotall)フラグは . を改行にもマッチさせます。グローバルの g と組み合わせれば、行をまたぐパターンで全マッチを取得できます: /^foo.+$/gms。
パターンとテキストはどこかへ送信される?
いいえ。パターン照合はブラウザ組み込みの JavaScript RegExp エンジンを使っています。サーバには何もアップロードされません。これは実際の本番ログデータ、内部 API のレスポンス、機密性のあるコンテンツに対してパターンをテストするときに重要です。
後読みは学ぶべき?
便利ですが必須ではありません。後読みを使うと、何かの後に続くテキストを、その "何か" をマッチに含めずにマッチできます。例: (?<=\$)\d+ はドル記号を消費せずに、ドル記号の後の数字にマッチします。PCRE、現代の JavaScript(ES2018 以降)、Python の regex モジュールでサポートされています。可搬性のあるパターンを書くなら、まず対象エンジンを確認してください。
(...) ではなく (?:...) を使うのはなぜ?
キャプチャなしグループ((?:...))はわずかに高速で、キャプチャ配列のスロットを使わず、マッチ結果をすっきり保ちます。選択や量指定のためにグループ化が必要だが、マッチしたテキストを取り出す必要がない場合はいつでも使ってください。(http|https):// は不要かもしれないキャプチャを作りますが、(?:http|https):// は作りません。
Unicode 文字をマッチさせる正しい方法は?
JavaScript では u フラグを付けて Unicode プロパティエスケープを使います: /\p{Letter}+/gu はあらゆる文字体系の文字列に連続してマッチします。u フラグなしだと \w は ASCII の単語文字にしかマッチしません。Python の re モジュールは Python 3 では既定で Unicode 対応です。Java では Pattern.UNICODE_CHARACTER_CLASS が必要です。ほとんどのエンジンには Unicode 対応する手段があるので、お使いのエンジンのドキュメントを確認してください。