ブログに戻る
Reference 2026-04-25

2026年正規表現チートシート

正規表現パターン、フラグ、テスト済みの例のクイックリファレンス。

正規表現の構文は、毎週使う人でも詳細を忘れるほど密度が高い。このチートシートは日常的に手が伸びる構文に加え、2026年時代の追加要素であるUnicodeプロパティエスケープと v フラグ、そして本番サービスを落とすパフォーマンスの罠までカバーします。

文字クラス

  • \d / \D — 数字 / 非数字
  • \w / \W — 単語文字(英字、数字、アンダースコア) / それ以外すべて
  • \s / \S — 空白 / 非空白
  • . — 改行以外の任意の文字 (s フラグで改行も含む)
  • [abc], [a-z], [^abc] — 集合、範囲、否定集合
  • \p{L}, \p{Script=Hiragana} — Unicodeプロパティエスケープ(uv フラグが必要)。\w はASCII限定なので、国際的なテキストには \p{L}

量指定子

  • ? — 0個または1個
  • + — 1個以上
  • {n}, {n,}, {n,m} — ちょうど、以上、範囲指定の回数
  • a* — aが0個以上
  • デフォルトは貪欲: 量指定子はパターンの残りが成功できる範囲で最長のマッチを取ります
  • ? を付けると怠惰版 — +? は最短マッチを取ります。古典的な用途は、タグの並んだ行全体ではなくタグ1つにマッチする <.+?>

アンカーと境界

  • ^$ — 文字列の先頭と末尾。m フラグ付きなら各行の先頭と末尾
  • \b / \B — 単語境界 / 非境界。\bcat\b は「cat」にマッチするが「category」にはしない
  • 境界の定義は \w に従うため、デフォルトではこれもASCII限定

グループと後方参照

  • (abc) — キャプチャグループ、左から番号付け
  • (?:abc) — 非キャプチャ。純粋なグループ化にはこちらを使い、番号を安定させアロケーションを節約
  • (?<name>abc) — 名前付きキャプチャ、match.groups.name で読む
  • \1\k<name> — 後方参照。(["'])(.?)\1 はどちらの引用符で囲まれた文字列にもマッチ

先読み・後読み

  • (?=x) / (?!x) — 肯定 / 否定の先読み
  • (?<=x) / (?<!x) — 肯定 / 否定の後読み (JavaScriptはES2018から)
  • 先読み・後読みは文字を消費しないため、パスワード規則や挿入位置のマッチングに最適。例: 3桁区切り /\B(?=(\d{3})+(?!\d))/g

フラグ

  • g — 最初だけでなくすべてのマッチ。exec と併用すると状態を持ち、交互マッチというバグの古典的な源
  • i — 大文字小文字を無視
  • m^$ が改行位置でもマッチ
  • s — ドットが改行にもマッチ
  • u — 正しいUnicode: サロゲートペアが1単位になり、プロパティエスケープが有効化
  • v (ES2024) — u の全機能に加え、[\p{L}--[aeiou]](母音以外の文字)のような集合演算と \p{RGI_Emoji} のような文字列プロパティ
  • y — スティッキー、ちょうど lastIndex の位置でマッチ。自作レキサーの構成要素

実戦で検証済みのパターン

メール(実用的):     ^[\w.+-]+@[\w-]+\.[\w.-]+$

IPv4オクテット厳密: ^(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)$

ISO 8601日付: ^\d{4}-\d{2}-\d{2}$

UUID v4: ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$

URLスラッグ: ^[a-z0-9]+(?:-[a-z0-9]+)*$

Hexカラー: ^#(?:[0-9a-fA-F]{3}){1,2}$

メールのパターンは意図的に緩くしています。RFC 5321に完全準拠するパターンは巨大で、それでもメールボックスの存在は分かりません。形式は緩く検証し、メール送信で確認しましょう。

破滅的バックトラッキング

障害を起こす唯一の正規表現の挙動です。重なり合う選択肢の上の入れ子量指定子 — (a+)+b(\w|\d)+$ のような形 — は、長い入力がほぼマッチして最後で失敗するとき、バックトラッキングエンジンに指数的な数の分割を試させます。40文字の悪意ある文字列がCPUコアを数分間占有し得ます。これがReDoSです。

防御:

  • 選択肢を重ならないようにし、すでに量指定されたグループへの量指定を避ける
  • . より明示的な文字クラスを好む
  • 線形時間エンジン(RE2、Rustのregexクレート)は構造的に免疫 — 代償は後方参照と先読み・後読みの不在
  • ユーザー提供のパターンをユーザー提供の入力に対してリクエストスレッドで実行しない。やむを得なければワーカーでタイムアウトを

効いてくる習慣

  • 一度コンパイルして再利用: ホットループ内の正規表現リテラルは一部のエンジンで状態を再生成する
  • 位置が分かっているならアンカーを — ^ はスキャンせず即座に不一致を確定させる
  • 複雑なパターンは名前付きのソース文字列から合成してコメント化
  • 敵対的な入力でテスト: 空文字列、非常に長いニアマッチ、ASCII外のUnicode

エンジンは構文以上に異なる

同じパターンでもエンジンによって挙動が変わることがあり、自分がどの系統の上にいるかを知っていれば微妙な移植バグを防げます。

  • バックトラッキングエンジン — JavaScript(V8のIrregexp)、PCRE2、Pythonのre、Javaのjava.util.regex。フル機能、最悪ケースは指数時間。
  • 線形時間エンジン — RE2(Goのregexpが使用)、Rustのregexクレート。オートマトンによるO(n)マッチング保証。後方参照と先読み・後読みなし。
  • ハイブリッド — .NETのNonBacktrackingモード、PCRE2のDFAマッチング関数。

Stack Overflowからパターンをコピーする前に確認すべき機能差: 後読み(16.4以前のSafariで未対応、Go/RE2に不在)、強欲な量指定子とアトミックグループ(PCREとJava専用 — JavaScriptは先読みと後方参照のトリックで模倣)、\p プロパティエスケープの対応範囲。特にJavaScriptでは、グローバルマッチの反復にはmatchAllを選びましょう。execループを脆くする共有lastIndex状態を回避できます。そして素の文字列を渡すString.replaceは最初の1件しか置換しないため、gフラグ付きの正規表現が必要なことを覚えておいてください。

sdk.is/regex-tester の正規表現テスターで、マッチのハイライトを見ながらパターンを磨きましょう。