正規表現の基本と実務でよく使うパターン集|JavaScript対応
正規表現は「文字列のパターンを記述するための言語」です。書き捨てのコードでも本番のバリデーションでも使いますが、記号の意味を覚えていないと読むことすらできません。この記事では、実務で必要になる範囲に絞って基本を整理し、そのままコピーして使えるパターンをまとめます。
基本の記号
まず、頻出する記号を一覧で押さえます。
| 記号 | 意味 | 例 |
|---|---|---|
. | 任意の1文字(改行を除く) | a.c → abc, axc |
* | 直前の要素を0回以上 | ab* → a, ab, abb |
+ | 直前の要素を1回以上 | ab+ → ab, abb |
? | 直前の要素を0回か1回 | ab? → a, ab |
{n,m} | 直前の要素をn回以上m回以下 | a{2,4} → aa, aaa, aaaa |
[] | 文字クラス(いずれか1文字) | [abc] → a か b か c |
[^] | 否定の文字クラス | [^0-9] → 数字以外 |
() | グループ化・キャプチャ | (ab)+ → ab, abab |
| | いずれか(OR) | cat|dog |
^ | 行頭 | ^A → Aで始まる |
$ | 行末 | z$ → zで終わる |
\d | 数字([0-9]と同等) | |
\w | 英数字とアンダースコア | |
\s | 空白文字(スペース・タブ・改行) |
\d \w \s は、大文字にすると意味が反転します。\D は「数字以外」、\S は「空白以外」です。
覚え方のコツ
記号を丸暗記するより、「何を」「何回」という 2 要素で捉えると整理しやすくなります。
[0-9]が「何を」=数字{3}が「何回」=ちょうど3回
これを組み合わせた [0-9]{3} は「数字がちょうど3個」を意味します。ほとんどの正規表現は、この組み合わせの繰り返しです。
実務で使うパターン集
以下は JavaScript の正規表現リテラルで記述しています。他言語でもほぼそのまま使えますが、エスケープの扱いが異なる場合があります。
郵便番号(日本)
/^\d{3}-\d{4}$/
ハイフンなしも許容する場合は、ハイフンを任意にします。
/^\d{3}-?\d{4}$/
電話番号(日本・ハイフンあり)
/^0\d{1,4}-\d{1,4}-\d{4}$/
日本の市外局番は 1〜4 桁と幅があるため、桁数を固定できません。厳密な検証が必要な場合は、正規表現ではなく市外局番の一覧を使った照合を検討してください。
日付(YYYY-MM-DD)
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/
月を (0[1-9]|1[0-2]) と書くことで 01〜12 に限定しています。ただし、この正規表現は 2 月 31 日を通してしまいます。 正規表現で暦の妥当性まで検証するのは現実的ではないため、形式チェックのみに使い、実在するかどうかは日付ライブラリで判定してください。
URL
/^https?:\/\/[\w.-]+(?:\/[\w.\-~:@!$&'()*+,;=%/?#\[\]]*)?$/
/ は正規表現リテラルの区切り文字と衝突するため、\/ とエスケープしています。
全角文字を含むか
/[^\x01-\x7E。-゚]/
半角英数記号と半角カタカナ以外、つまり全角文字が含まれるかを判定します。入力フォームで全角混入をチェックする用途に使えます。
HTMLタグを除去する
text.replace(/<[^>]*>/g, "")
簡易的なタグ除去です。ただし、これは信頼できない入力のサニタイズには使ってはいけません。 属性値の中に > が含まれるケースなど、この正規表現では対応できないパターンが存在します。セキュリティ目的では専用のサニタイズライブラリを使ってください。
連続する空白を1つにまとめる
text.replace(/\s+/g, " ").trim()
改行やタブを含むすべての空白をスペース1つに正規化します。テキスト整形で頻繁に使うパターンです。
メールアドレスの検証について
メールアドレスの正規表現は、検索すると極端に長いものが出てきます。実は RFC に完全準拠した正規表現は数千文字になり、実用性がありません。
実務では、次の 2 段階に分けるのが現実的です。
- 形式チェックは緩い正規表現で行う
- 実在確認は確認メールの送信で行う
形式チェックには、この程度で十分です。
/^[^\s@]+@[^\s@]+\.[^\s@]+$/
「@ の前後に空白でない文字があり、ドメイン部にドットが 1 つ以上ある」という条件です。厳しすぎる正規表現は、有効なアドレスを弾いてしまうリスクのほうが大きくなります。
よくある落とし穴
貪欲マッチ(greedy)
* と + は、可能な限り長くマッチしようとします。これを貪欲マッチと呼びます。
"<b>A</b><b>B</b>".match(/<b>.*<\/b>/)
// → "<b>A</b><b>B</b>" 全体にマッチしてしまう
最短マッチにするには、? を付けます。
"<b>A</b><b>B</b>".match(/<b>.*?<\/b>/)
// → "<b>A</b>"
意図しない範囲がマッチする場合、まずこの貪欲マッチを疑ってください。
特殊文字のエスケープ漏れ
. * + ? ( ) [ ] { } ^ $ | \ / は正規表現上の特別な意味を持ちます。文字そのものとして扱いたい場合はバックスラッシュでエスケープします。
/\./ // ドットそのもの
/\$/ // ドル記号そのもの
. をエスケープし忘れると「任意の1文字」として解釈され、意図しない文字列にマッチします。
^ と $ を付け忘れる
/\d{3}/.test("abc123def") // → true
^ $ がないと「文字列のどこかに含まれるか」の判定になります。バリデーションでは「文字列全体が一致するか」を見たいはずなので、必ず ^ と $ で囲んでください。
/^\d{3}$/.test("abc123def") // → false
全体をキャプチャする括弧を多用する
() はグループ化と同時にキャプチャ(後で参照できるよう記憶)を行います。参照しないグループには (?:...) を使うと、余計なキャプチャが発生しません。
/(?:abc)+/ // グループ化のみ、キャプチャしない
パターンの検証方法
正規表現は、頭の中で動作を追うと必ずと言っていいほど間違えます。必ず実際の文字列で試してください。
正規表現テスターツールを使うと、パターンとテスト文字列を入力してマッチ箇所をリアルタイムでハイライト確認できます。置換結果の確認にも対応しているため、replace を書く前の検証にも使えます。
検証の際は、次の 3 種類の入力を必ず試してください。
- 通過すべき正常系 — 想定どおりマッチするか
- 弾くべき異常系 — 誤ってマッチしていないか
- 境界値 — 桁数の上限・下限、空文字列
特に 2 番目が抜けがちです。「マッチした」だけを確認して、「マッチしてはいけないものが通っていないか」を見落とすと、バリデーションが機能しません。
まとめ
- 記号は「何を」「何回」の2要素で捉える
^と$を付けないと部分一致になる*+は貪欲。最短にしたいなら?を付ける- メールアドレスの完全な検証は正規表現では行わない
- 書いたら必ずテスターツールで正常系・異常系の両方を確認する
正規表現は「一度書いて終わり」ではなく、想定外の入力が来るたびに調整するものです。テストしやすい形で残しておくことが、結局いちばん早道になります。