フォームの検証
携帯電話番号、郵便番号、日付の形式、パスワード強度——第 22–24 レッスンの 3 つのパターンはそのままフロントエンドのフォームに使えます。アンカーを忘れずに付け、「2 月 30 日」のような意味のチェックはコードに任せてください。
Guide
正規表現講座は 25 レッスンの対話形式チュートリアルです。各レッスンにはテストテキストと目標(「これらに一致させ、あれらには一致させない」または「ある部分を捕獲する」)があり、入力欄で式を書き換えると右側で一致とグループがリアルタイムにハイライトされ、判定がどの目標を達成したかを項目ごとに示します。判定はすべてブラウザー内蔵の JavaScript 正規表現エンジンで行われ、テキストは一切アップロードされません。
更新日 2026-09-094 sources13 min read
正規表現講座は 25 レッスンの対話形式チュートリアルです。各レッスンにはテストテキストと目標(「これらに一致させ、あれらには一致させない」または「ある部分を捕獲する」)があり、入力欄で式を書き換えると右側で一致とグループがリアルタイムにハイライトされ、判定がどの目標を達成したかを項目ごとに示します。判定はすべてブラウザー内蔵の JavaScript 正規表現エンジンで行われ、テキストは一切アップロードされません。
講座は難易度順に進みます。まずリテラル、ドット、エスケープという「文字を探す」基礎。次に文字クラスと範囲、定義済みクラス \d \w \s、4 つの量指定子。続いてアンカーと単語境界、選択、3 種類のグループと後方参照、最長一致と最短一致。さらに先読み / 後読みとフラグ。最後に 3 つの実用パターン(中国本土の携帯電話番号、メール、日付)で総合練習し、「壊滅的バックトラック」のレッスンで締めくくります。自分でエンジンを止めてしまう式を書き、それを直します。
学習時間は約 60 分。正規表現を書いたことがない人、「コピーはするが書き換えられない」人に向いています。すでに慣れている読者は第 17 レッスン以降の先読み・後読みと罠の部分へ直接進んでください。
?lesson=n 付きのリンクをコピーし、開くとそのレッスンから始まります。「進捗をリセット」はこの講座の記録をすべて消します。このページの上部が講座本体です。左の目次でレッスンを選び、中央に正規表現を入力すると、判定がその場で現れます。
第 14 レッスン「捕獲グループ」の目標は 2026-09-09 から年を取り出すことです。以下はあるクリアまでの記録です。
テストテキスト 公開日:2026-09-09、締切:2027-01-31
1 回目 \d+
一致 2026 09 09 2027 01 31 ← 6 か所に一致、捕獲グループなし
判定 ✕ 完全な日付 2 つだけに一致すべき ✕ グループ 1 は年であるべき
2 回目 (\d{4})-\d{2}-\d{2}
一致 2026-09-09 2027-01-31 ← 2 か所に一致
グループ 1 2026 2027
判定 ✓ 一致数 2 ✓ グループ 1 = 2026 / 2027 → クリア
第 25 レッスン「壊滅的バックトラック」は逆の流れです。まず ^(a+)+$ のような入れ子の量指定子を書き、aaaaaaaaaaaaaaaaaaaaaaaaaaaa! の文字列でテストすると、ページが試行回数の指数関数的な増加を報告します。次に ^a+$ のような等価な書き方に直してクリアします。
正規表現(regular expression)は、小さな記号の集合で「ある種の文字列がどんな形か」を記述します。英数字は多くがそれ自身を表し、十数個のメタ文字(. * + ? ^ $ | ( ) [ ] { } \)は特別な意味を持ちます。エンジンはパターンを手にテキストを左から右へ走査し、各位置で一致を試み、見つかれば位置と長さを報告します。この講座は JavaScript(ECMAScript)の方言を使います。Python、Java、Go の正規表現と基礎文法はほぼ同じで、差は先読み・後読み、Unicode プロパティ、一部のフラグに集中しています。
cat は連続する c、a、t の 3 文字に一致します。ドット . は改行以外の任意の 1 文字に一致するので、c.t は cat、cut、c9t に一致します。本当にピリオド(たとえば拡張子の前の点)を探したいときは \. と書きます。バックスラッシュがメタ文字を文字そのものの意味に戻します。メタ文字はすべてこのようにエスケープでき、文字クラスの中では ] \ ^ - だけをエスケープすれば十分です。
角括弧は候補の文字を並べます。[aeiou] はどの母音にも一致し、[a-z]、[0-9] はハイフンで範囲を表し、[A-Za-z0-9_] のように並べて書けます。先頭に ^ を付けると否定になり、[^0-9] は数字以外の任意の文字に一致します。よく使う定義済みクラスはその省略形です。
| クラス | 等価な書き方 | 説明 |
|---|---|---|
\d |
[0-9] |
数字(漢数字と全角数字は含まない) |
\w |
[A-Za-z0-9_] |
「単語の文字」。漢字は含まれない点に注意 |
\s |
[ \t\n\r\f\v…] |
空白。全角スペースを含む |
大文字版の \D \W \S はそれぞれの否定です。\w に漢字が含まれないのは日本語や中国語の利用者が最もよく踏む罠です。漢字に一致させたいときは [\u4e00-\u9fa5] と書くか、u フラグの下で \p{Script=Han} を使います。
量指定子は原子(1 文字、文字クラス、グループのいずれか)の後ろに付き、その繰り返し回数を決めます。
* は 0 回以上、+ は 1 回以上、? は 0 回または 1 回。{n} はちょうど n 回、{n,} は n 回以上、{n,m} は n 回から m 回。\d{4} は \d\d\d\d より読みやすく、\d{11} は携帯電話番号の桁数です。量指定子はすぐ前の 1 つの原子にしか働きません。ab+ は a の後に b が 1 つ以上で、ab 全体を繰り返すには (ab)+ と書きます。
^ と $ は文字ではなく位置に一致します。文字列の先頭と末尾(複数行モードでは各行の先頭と末尾)です。フォームの検証ではほぼ必ず ^…$ を書きます。そうしないと \d{11} は 12 桁の番号の先頭 11 桁に「一致」してしまいます。\b は単語境界で、\w と \W(または文字列の端)の間の位置です。\bcat\b は a cat に一致し、concatenate には一致しません。ここでも \w に漢字が含まれないため、\b は日本語のテキストではほとんど役に立ちません。
| は「または」を表し、優先順位は最も低いです。cat|dog は 2 つの語のどちらかに一致します。範囲を限定するには括弧を使い、gr(a|e)y とします。括弧は同時に捕獲グループを作ります。一致に成功すると番号でグループ内のテキストを取り出せ(match[1])、置換文字列では $1 で参照できます。これは正規表現でもっとも生産的な使い方の 1 つで、たとえば 2026-09-09 を 09/09/2026 にするのは replace 1 回で済みます。
(?<year>\d{4}) は名前付きグループで、groups.year で読めます。数字の番号より、パターンを書き換えたときにずれにくい方法です。(?:…) は非捕獲グループで、グループ化だけを行い番号を消費しません。量指定子や選択の範囲を決めたいだけのときに使います。\1 は後方参照です。ここにもう一度グループ 1 が捕獲した内容が現れることを要求します。(\w)\1 は ll、oo のような同じ文字の重なりに一致し、<(\w+)>.*?</\1> は対になった HTML タグに一致します。
量指定子は既定で欲張りです。できるだけ多く取り、取りすぎたら戻します。"a" and "b" に対して ".+" は最初の引用符から最後の引用符まですべてを一度に一致させます。量指定子の後ろに ? を付けると最短一致になります。".+?" はできるだけ少なく取り、"a" と "b" の 2 つに一致します。より正確な書き方は否定文字クラス "[^"]+" です。これはバックトラックに頼らないため、通常は速くもなります。
先読み・後読み(lookaround)はアンカーと同じく位置だけに一致しますが、条件は「隣にそのパターンがあるかどうか」です。
(?=…) 先読み: 後ろに … が続く必要があります。\d+(?=px) は 100px の中の 100 に一致し、「px」は一致に含めません。(?!…) 否定先読み: 後ろが … であってはいけません。(?<=…) 後読み: 前に … がある必要があります。(?<=¥)\d+ は通貨記号を含まずに価格の数字に一致します。(?<!…) 否定後読み。JavaScript は ES2018 から後読みに対応し、Safari で完全に使えるようになったのは 16.4 以降です。Python の後読みは固定長を要求します。パスワード強度の検証は先読みの典型例です。^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$ は 3 つの先読みで同じ位置から「数字を含む、小文字を含む、大文字を含む」をそれぞれ確認し、そのあと .{8,} が文字列全体を消費します。
フラグはパターンの外に書きます。i は大文字小文字を無視、g は最初の 1 つではなくすべての一致を探し(講座のハイライトは常に g を使います)、m は ^ $ を各行に一致させ、s は . を改行にも一致させ、u は Unicode モードを有効にして . を UTF-16 コード単位ではなくコードポイント単位で一致させ(絵文字が 1 文字と数えられます)、y は粘着一致で lastIndex の位置から直ちに一致しなければなりません。
中国本土の携帯電話番号: ^1[3-9]\d{9}$——1 で始まり、2 桁目が 3–9 で、全部で 11 桁。事業者ごとの番号帯を列挙しようとしないでください。番号帯は毎年増えています。
メール: RFC 5322 に完全準拠した正規表現は数千文字になり、実用的でもありません。フォームでの妥当な書き方は ^[^\s@]+@[^\s@]+\.[^\s@]+$ です。@ がちょうど 1 つ、両側が空でない、ドメイン部分に少なくとも 1 つの点。本当の検証は確認メールを送ることです。
日付: ^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ は月を 01–12、日を 01–31 に限定できますが、2 月が何日あるかは分かりません。文法の検証は正規表現に、意味の検証はコードにです。
JavaScript、Python、Java、PCRE の正規表現エンジンはバックトラック方式です。複数の分け方があればまず 1 つ試し、失敗したら戻って次を試します。入れ子の量指定子は分け方の数を指数的に増やします。^(a+)+$ が 30 個の a と 1 つの ! に向き合うと、エンジンは失敗を宣言するまで 2^30 通りを超える分割を試す必要があり、ブラウザーのタブは数秒から数分固まります。こうしたパターンが利用者の入力を受け取るなら、サービス妨害攻撃(ReDoS)になります。
避けるための原則は次のとおりです。隣り合う 2 つの量指定子が同じ文字に一致し得る状態を作らない((a+)+、(\w+\s?)+、(.*)* は危険信号です)。最短一致の .*? の代わりに否定文字クラスを使う。入力に長さの上限を設ける。Go と Rust の正規表現ライブラリは Thompson NFA / DFA の実装で線形時間を保証しますが、代償として後方参照と先読み・後読みが使えません。Russ Cox の記事が両方式の違いを最も明快に説明しています。
入れ子構造の一致(括弧の対応、HTML 全体)、「数える」必要のある作業(左右の括弧の数が等しいかの判定)、文脈に依存する意味の判断(この数字が正しい日付かどうか)は、正規表現にはできないか、極端に難しくなります。正規表現は字句の層の道具です。トークンを見つける、分割する、簡単に検証する、一括置換する——これらにおいて代えがききません。
(?i) インライン修飾子、Python の (?P<name>)、Java の \p{javaLowerCase} などの方言差や、POSIX 文字クラス [[:alpha:]] は扱いません。u を簡単に紹介するだけです。\p{…} のプロパティエスケープと v フラグの集合演算は講座の範囲外です。\w は漢字に一致する」: 一致しません。\w は ASCII の英字、数字、アンダースコアだけで、漢字に一致させるには [\u4e00-\u9fa5] か \p{Script=Han}(u フラグが必要)を使います。. はどんな文字にも一致する」: 既定では改行に一致しません。行をまたぐなら s フラグを付けるか [\s\S] を使います。\d{11} と書けば 11 桁しか受け付けない」: アンカーがなければ、より長い数字列の中から 11 桁を見つけてしまいます。検証には必ず ^…$ を付けます。[A-z] はすべての英字」: ASCII では大文字 Z(90)と小文字 a(97)の間に [ \ ] ^ _ \`` の 6 記号があり、それらも一緒に一致します。[A-Za-z]` と書きましょう。ab+ が繰り返すのは b だけです。ab{2} は abb に一致し、abab には一致しません。>、コメントがあると正規表現は破綻します。DOM パーサーを使ってください。携帯電話番号、郵便番号、日付の形式、パスワード強度——第 22–24 レッスンの 3 つのパターンはそのままフロントエンドのフォームに使えます。アンカーを忘れずに付け、「2 月 30 日」のような意味のチェックはコードに任せてください。
VS Code、Sublime、JetBrains 系の検索と置換は正規表現と $1 の参照に対応しています。グループの節を学べば、2026-09-09 をすべて 09/09/2026 に一度で変えたり、すべての console.log( に接頭辞を付けたりできます。
数万行のログから IP、ステータスコード、所要時間を取り出します。(\d+\.\d+\.\d+\.\d+).*?" (\d{3}) (\d+)ms のようなパターンを名前付きグループと組み合わせれば、数行のスクリプトで集計できます。
(\w+\s?)+$、(.*a)+、(a|aa)+ のような入れ子・重複した量指定子が利用者入力を処理する場所にあれば、書き換えるか長さ制限を加えるよう求めるべきです。
判定が見るのは書き方ではなく結果です。一致すべきものがすべて当たり、一致すべきでないものがすべて外れ、捕獲グループの内容が一致していればクリアです。参考の式はそのうちの 1 通りにすぎません。
多くは「一致すべきでない」断片にも一致しているか、一致範囲が目標より 1 文字多い(約物を飲み込んでいるなど)ためです。結果バーのどこが ✕ かを確認してください。
第 1–18 レッスンの文法は主要言語でほぼそのまま通用します。先読み・後読みのレッスンのうち後読みは Python では固定長が必要で、名前付きグループは Python では (?P<name>…) と書きます。フラグの書き方は言語ごとに異なります。
このブラウザーの localStorage に保存され、アップロードされません。ブラウザーを変えたりサイトデータを消したりすると失われます。「このレッスンを共有」のリンクで、どこまで進んだかを控えておけます。
デモは模擬的なステップ数の計数を使い、しきい値を超えると「壊滅的バックトラック」と判定します。実際に実行するとタブ全体が応答しなくなり、フィードバックを返せません。
講座は完全にブラウザー内で動作します。入力した式とテストテキストはブラウザー内蔵の正規表現エンジンに渡されるだけで、どのサーバーにも送信されません。クリア状況は端末の localStorage に保存されます。ページを閉じると入力内容は解放されます。
更新日 2026-09-09
全 25 レベルで学ぶ対話型正規表現。リテラル、文字クラス、量指定子、グループ、ルックアラウンド、バックトラックの落とし穴まで、変更は即反映
このツールの翻訳は未完了です。一部は原文または代替言語で表示されます。
目標cat を含むすべての単語に一致し、それ以外には一致しない式を作成します。
最も単純な正規表現は、通常の文字の連続です。 cat は、テキスト内で連続する c、a、t を検索します。デフォルトでは、正規表現は「等しい」ではなく「含む」を意味します。concat と category には cat が含まれているため、これらも一致します。文字、数字、スペース、CJK 文字はすべてリテラルです。特別な記号は 12 個ほどだけで、次のレッスンで 1 つずつ説明します。