正規表現: 実例付き実践ガイド
· 12分で読めます
正規表現(regex)は開発者のツールキットの中で最も強力なツールの一つですが、しばしば誤解されたり、完全に避けられたりしています。ユーザー入力の検証、ログファイルの解析、テキストデータの変換など、正規表現は文字列内のパターンマッチングを簡潔かつ効率的に行う方法を提供します。
この包括的なガイドでは、正規表現の基礎から高度なテクニックまで、プロジェクトですぐに使える実例とともに解説します。最後には、正規表現がどのように機能するかだけでなく、いつ、なぜ使うべきかを理解できるでしょう。
目次
正規表現とは何か、なぜ気にすべきか?
正規表現は、検索パターンを定義する文字の並びです。テキスト内のパターンマッチング専用に設計されたミニ言語と考えてください。正確な文字列を検索する代わりに、正規表現では「任意のメールアドレス」や「この形式のすべての電話番号」のようなパターンを記述できます。
正規表現は、ほぼすべてのプログラミング言語と多くのコマンドラインツールでサポートされています。構文を一度学べば、JavaScriptやPythonからgrepやsedまで、どこでも適用できます。
一般的な使用例:
- ユーザー入力の検証(メール、電話番号、パスワード)
- テキストからのデータ抽出(ログの解析、コンテンツのスクレイピング)
- 検索と置換操作(コードのリファクタリング、データのクリーニング)
- URLルーティングとパターンマッチング
- シンタックスハイライトと字句解析
プロのヒント: 正規表現は強力ですが、常に適切なツールとは限りません。HTMLやJSONのような複雑な解析タスクには、専用のパーサーを使用してください。正規表現は、明確に定義された比較的シンプルなパターンに最適です。
正規表現の基礎: 構成要素
すべての正規表現パターンは、基本的な構成要素から構築されます。より複雑なパターンに進む前に、これらのコア要素を理解することが不可欠です。
リテラル文字
最もシンプルな正規表現は、単なるリテラルテキストです。パターンcatは、テキスト内の正確な文字列「cat」にマッチします。ほとんどの英数字は直接自分自身にマッチします。
メタ文字
特定の文字は正規表現で特別な意味を持ちます。これらはメタ文字と呼ばれ、次のものが含まれます: . ^ $ * + ? { } [ ] \ | ( )
これらの文字をリテラルとしてマッチさせるには、バックスラッシュでエスケープする必要があります。例えば、\.はリテラルのピリオドにマッチします。
ドットワイルドカード
ドット.は最も基本的なワイルドカードで、改行以外の任意の1文字にマッチします。パターンa.cは「abc」、「a1c」、「a-c」にマッチしますが、「ac」(間に文字がない)や「a\nc」(改行)にはマッチしません。
| パターン | マッチ対象 | 例 |
|---|---|---|
. |
任意の文字(改行を除く) | a.cはabc、a1c、a-cにマッチ |
\d |
任意の数字[0-9] | \d{3}は123、456にマッチ |
\w |
単語文字[a-zA-Z0-9_] | \w+はhello、user_1にマッチ |
\s |
空白文字(スペース、タブ、改行) | \s+はスペース、タブにマッチ |
\D |
数字以外 | \D+はabc、xyzにマッチ |
\W |
単語文字以外 | \W+は!@#、スペースにマッチ |
\S |
空白文字以外 | \S+は任意の可視テキストにマッチ |
大文字版(\D、\W、\S)は小文字版の逆であることに注意してください。これは正規表現構文の一般的なパターンです。
量指定子: 繰り返しの制御
量指定子は、パターンが何回繰り返されるべきかを指定します。繰り返したい要素の後に配置され、柔軟なパターンを作成するための基本です。
基本的な量指定子
| 量指定子 | 意味 | 例 |
|---|---|---|
* |
0回以上 | ab*cはac、abc、abbc、abbbcにマッチ |
+ |
1回以上 | ab+cはabc、abbc(acではない)にマッチ |
? |
0回または1回(オプション) | colou?rはcolor、colourにマッチ |
{n} |
正確にn回 | \d{4}は2026、1999にマッチ |
{n,} |
n回以上 | \d{3,}は123、1234、12345にマッチ |
{n,m} |
n回からm回 | \d{2,4}は12、123、1234にマッチ |
貪欲マッチと最小マッチ
デフォルトでは、量指定子は貪欲です—できるだけ多くのテキストにマッチします。これは、HTMLタグのようなパターンをマッチさせる際に予期しない結果につながる可能性があります。
// 貪欲マッチ
const text = "<div>Hello</div><div>World</div>";
const greedy = /<.*>/;
// マッチ: "<div>Hello</div><div>World</div>" (文字列全体!)
// 最小マッチ
const lazy = /<.*?>/;
// マッチ: "<div>" (最初の閉じ括弧で停止)
量指定子の後に?を追加すると、最小(非貪欲)になります。最小量指定子は、パターンを満たしながらできるだけ少ないテキストにマッチします。
クイックヒント: 区切り文字(引用符、括弧、タグ)間のコンテンツをマッチさせる場合、通常は最小量指定子が必要です。マッチしすぎを避けるために、.*の代わりに.*?を使用してください。
文字クラスとショートカット
文字クラスを使用すると、特定のセットから任意の文字にマッチできます。角括弧を使用して定義され、柔軟なパターンを作成するのに非常に便利です。
基本的な文字クラス
// 任意の母音にマッチ
/[aeiou]/
// 任意の数字にマッチ
/[0-9]/
// 任意の小文字にマッチ
/[a-z]/
// 任意の文字にマッチ(大文字小文字を区別しない)
/[a-zA-Z]/
// 英数字にマッチ
/[a-zA-Z0-9]/
否定文字クラス
文字クラスの先頭で^を使用すると否定され、リストされた文字以外の任意の文字にマッチします。
// 数字以外にマッチ
/[^0-9]/
// 母音以外にマッチ
/[^aeiou]/
// スペースまたはタブ以外の任意の文字にマッチ
/[^ \t]/
クラス内の特殊文字
ほとんどのメタ文字は文字クラス内で特別な意味を失います。.、*、+、?をエスケープせずに含めることができます。ただし、特定の位置では]、\、^、-をエスケープする必要があります。
// ピリオドまたはカンマにマッチ
/[.,]/
// ハイフンにマッチ(エスケープするか先頭/末尾に配置)
/[-a-z]/ または /[a-z-]/
// 閉じ括弧にマッチ(エスケープ必須)
/[\]]/
グループとキャプチャ
グループには2つの主な目的があります: 複数の文字に量指定子を適用できること、そしてマッチしたテキストを後で使用するためにキャプチャすることです。
キャプチャグループ
括弧はマッチしたテキストを記憶するキャプチャグループを作成します。これは文字列からデータを抽出するために不可欠です。
// 日付コンポーネントを抽出
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2026-03-29".match(datePattern);
// match[0]: "2026-03-29" (完全マッチ)
// match[1]: "2026" (最初のグループ)
// match[2]: "03" (2番目のグループ)
// match[3]: "29" (3番目のグループ)
名前付きキャプチャグループ
名前付きグループは正規表現をより読みやすくし、コードをより保守しやすくします。番号でグループを参照する代わりに、説明的な名前を付けます。
// 名前付きグループの構文: (?<name>pattern)
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = "2026-03-29".match(datePattern);
// 名前でアクセス
console.log(match.groups.year); // "2026"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "29"
非キャプチャグループ
量指定子や選択のためにグループ化が必要だが、テキストをキャプチャしたくない場合があります。非キャプチャグループは(?:...)構文を使用します。
// グループを作成せずにプロトコルをキャプチャ
/(?:https?|ftp):\/\/([a-z.]+)/
// これは1つのキャプチャグループ(ドメイン)のみを作成
// プロトコルグループ(?:https?|ftp)はキャプチャしない
非キャプチャグループはキャプチャグループよりも高速でメモリ使用量が少なくなります。キャプチャしたテキストが不要な場合に使用してください。
後方参照
後方参照を使用すると、前のグループでキャプチャされたのと同じテキストにマッチできます。これは繰り返される単語を見つけたり、ペアの区切り文字をマッチさせるのに便利です。
// 繰り返される単語を見つける
/\b(\w+)\s+\1\b/
// "the the"や"hello hello"にマッチ
// ペアの引用符にマッチ
/(['"])(.*?)\1/
// "hello"や'world'にマッチするが"mixed'にはマッチしない
選択
パイプ|演算子は選択を作成し、1つのパターンまたは別のパターンにマッチします。論理ORのようなものです。
// cat、dog、またはbirdにマッチ
/cat|dog|bird/
// 一般的なファイル拡張子にマッチ
/\.(jpg|jpeg|png|gif|webp)$/i
// Mr.、Mrs.、Ms.、またはDr.にマッチ
/(?:Mr|Mrs|Ms|Dr)\./
アンカーと境界
アンカーは文字にマッチしません—文字列内の位置にマッチします。パターンが特定の場所に現れることを保証するために不可欠です。
文字列アンカー
^は文字列の先頭にマッチ(複数行モードでは行の先頭)$は文字列の末尾にマッチ(複数行モードでは行の末尾)
// "Hello"で始まる必要がある
/^Hello/
// "world"で終わる必要がある
/world$/
// 文字列全体が正確に5桁である必要がある
/^\d{5}$/
単語境界
\bアンカーは単語境界にマッチします—単語文字と非単語文字の間の位置です。これは完全な単語をマッチさせるために重要です。
// "cat"を完全な単語としてマッチ
/\bcat\b/
// マッチ: "cat"、"the cat sat"
// マッチしない: "category"、"scat"
// "pre"で始まる単語にマッチ
/\bpre\w+/
// マッチ: "preview"、"prepare"、"prefix"
逆の\Bは非単語境界にマッチします—両側が単語文字であるか、両側が非単語文字である位置です。
プロのヒント: 完全な単語を検索する場合は、常に単語境界を使用してください。それらがないと、「cat」を検索すると「category」や「concatenate」にもマッチします。パターン\bcat\bは完全な単語のみにマッチすることを保証します。
実用的な一般的パターン
一般的な検証と抽出タスクのための実証済みの正規表現パターンです。これらのパターンはシンプルさと実用的な精度のバランスを取っています。
| パターンタイプ | 正規表現 | 備考 |
|---|---|---|
| メール(シンプル) | ^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$ |
基本的な検証に適している |
| メール(RFC準拠) | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ |
より厳格、広く受け入れられている |
| URL | ^https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/\S*)?$ |
基本的なHTTP/HTTPS URL |
| IPv4アドレス | ^(?:\d{1,3}\.){3}\d{1,3}$ |
形式のみ、範囲は検証しない |
| IPv4(厳格) | ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ |
0-255の範囲を検証 |
| 日付(YYYY-MM-DD) | ^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ |
ISO 8601形式 |
| 時刻(24時間) | ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$ |
HH:MMまたはHH:MM:SS |
| 電話(米国) | ^\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$ |
柔軟な形式 |
| 16進数カラー | ^#(?:[0-9a-fA-F]{3}){1,2}$ |
3桁または6桁の16進数コード |
| クレジットカード | ^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$ |
形式のみ、検証にはLuhnを使用 |
| ユーザー名 | ^[a-zA-Z0-9_-]{3,16}$ |
3-16文字、英数字と_と- |
| スラッグ | ^[a-z0-9]+(?:-[a-z0-9]+)*$ |
URL対応の小文字とハイフン |
パスワード検証
パスワード検証には、複数の条件を同時にチェックする必要があります。先読みアサーションにより、複雑なロジックなしでこれが可能になります。
// 強力なパスワード: 8文字以上、大文字、小文字、数字、特殊文字
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
// 分解すると:
// (?=.*[a-z]) - 少なくとも1つの小文字
// (?=.*[A-Z]) - 少なくとも1つの大文字