正規表現: 開発者のための実践ガイド
· 12分で読めます
目次
正規表現(regex)は、開発者のツールキットの中で最も強力なツールの一つです。パターン記述を使用してテキストを検索、マッチング、操作するための簡潔で柔軟な方法を提供します。ユーザー入力の検証、ログファイルの解析、APIからのデータ抽出、複雑な検索置換操作など、正規表現の知識は効率的な開発に不可欠です。
この包括的なガイドでは、基礎から高度なパターンまで、実践的な実例とともに学習します。最後には、構文だけでなく、プロジェクトで正規表現を効果的に適用するタイミングと方法を理解できるようになります。
正規表現の基礎
正規表現の核心は、検索パターンを定義する文字列です。テキストパターンを記述するためのミニ言語と考えてください。すべての正規表現パターンの基礎となる基本的な構成要素から始めましょう。
リテラル文字
最も単純な正規表現はリテラル文字列です。パターンhelloは入力内の正確なテキスト「hello」にマッチします。ほとんどの文字は文字通りに自分自身にマッチするため、基本的な検索は簡単です。
ただし、特定の文字は正規表現で特別な意味を持ち、メタ文字と呼ばれます。これらを文字通りにマッチさせたい場合は、バックスラッシュでエスケープする必要があります:
. ^ $ * + ? { } [ ] \ | ( )
例えば、リテラルのピリオドにマッチさせるには、.だけでなく\.を使用します。ドル記号にマッチさせるには、\$を使用します。
アンカー
アンカーは文字にマッチするのではなく、テキスト内の位置にマッチします。正確なパターンマッチングに不可欠です:
^— 行または文字列の先頭にマッチ$— 行または文字列の末尾にマッチ\b— 単語境界(単語文字と非単語文字の間)\B— 非単語境界(\bの反対)\A— 文字列の先頭(一部のフレーバーでは、複数行モードで^と異なる)\Z— 文字列の末尾(一部のフレーバーでは、複数行モードで$と異なる)
例: パターン^Hello$は、前後に他のテキストがない「Hello」だけを含む行にのみマッチします。
例: パターン\bcat\bは単語全体としての「cat」にマッチしますが、「category」や「concatenate」内の「cat」にはマッチしません。
プロのヒント: 部分マッチを防ぐためにアンカーを使用してください。メールアドレスや電話番号を検証する際は、常に^と$でパターンをアンカーし、文字列の一部だけでなく全体がパターンにマッチすることを確認してください。
文字クラスと量指定子
文字クラスと量指定子は、正規表現が真に強力になる部分です。文字の範囲にマッチさせたり、パターンが繰り返される回数を指定したりできます。
文字クラス
文字クラスは、定義されたセットから任意の1文字にマッチします。角括弧で囲まれます:
[abc]— a、b、またはcにマッチ[a-z]— 任意の小文字にマッチ[A-Z0-9]— 任意の大文字または数字にマッチ[^abc]— a、b、c以外の任意の文字にマッチ(否定クラス).— 改行以外の任意の文字にマッチ
複数の範囲を組み合わせることができます:[a-zA-Z0-9]は任意の英数字にマッチします。
短縮文字クラス
これらの定義済みクラスは時間を節約し、可読性を向上させます:
| 短縮形 | 同等の表現 | 説明 |
|---|---|---|
\d |
[0-9] |
任意の数字 |
\D |
[^0-9] |
任意の非数字 |
\w |
[a-zA-Z0-9_] |
任意の単語文字(文字、数字、アンダースコア) |
\W |
[^a-zA-Z0-9_] |
任意の非単語文字 |
\s |
[ \t\n\r\f\v] |
任意の空白文字 |
\S |
[^ \t\n\r\f\v] |
任意の非空白文字 |
量指定子
量指定子は、直前の要素が何回マッチすべきかを指定します:
*— 0回以上(貪欲)+— 1回以上(貪欲)?— 0回または1回(オプション){n}— 正確にn回{n,}— 少なくともn回{n,m}— n回からm回の間(両端を含む)
例: \d{3}-\d{2}-\d{4}は「123-45-6789」のような社会保障番号の形式にマッチします。
例: colou?rは「color」と「colour」の両方にマッチします('u'はオプション)。
貪欲vs最小マッチ量指定子
デフォルトでは、量指定子は貪欲です—できるだけ多くのテキストにマッチします。量指定子の後に?を追加すると最小マッチ(非貪欲)になり、できるだけ少なくマッチします:
*?— 0回以上(最小マッチ)+?— 1回以上(最小マッチ)??— 0回または1回(最小マッチ){n,m}?— n回からm回の間(最小マッチ)
例: テキスト<div>content</div>に対して、パターン<.+>(貪欲)は文字列全体にマッチしますが、<.+?>(最小マッチ)は<div>のみにマッチします。
クイックヒント: 区切り文字(HTMLタグや引用符など)の間のコンテンツを抽出する際は、常に最小マッチ量指定子を使用して、マッチしすぎを避けてください。パターン".*?"は引用符で囲まれた文字列を正しく抽出しますが、".*"は行全体の最初の引用符から最後の引用符までマッチしてしまいます。
グループ、キャプチャ、後方参照
グループを使用すると、複数の文字を単一のユニットとして扱い、マッチしたテキストを後で使用するためにキャプチャできます。複雑なパターンやテキスト抽出に不可欠です。
キャプチャグループ
括弧()はキャプチャグループを作成します。マッチしたテキストは保存され、後で参照できます:
(\d{3})-(\d{3})-(\d{4})
このパターンは電話番号にマッチし、3つのグループをキャプチャします:市外局番、プレフィックス、回線番号。ほとんどの言語では、これらのキャプチャに$1、$2、$3または類似の構文でアクセスできます。
非キャプチャグループ
量指定子や選択のためにグループ化が必要だが、テキストをキャプチャする必要がない場合があります。非キャプチャグループには(?:...)を使用します:
(?:https?|ftp)://[^\s]+
これはhttp、https、またはftpで始まるURLにマッチしますが、プロトコルを個別にキャプチャしません。キャプチャしたテキストが不要な場合、非キャプチャグループの方が効率的です。
名前付きキャプチャグループ
名前付きグループは正規表現をより読みやすく保守しやすくします。構文は言語によって異なります:
- Python、.NET、PCRE:
(?P<name>...)または(?<name>...) - JavaScript (ES2018+):
(?<name>...)
例:
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
これは日付にマッチし、年、月、日の名前付きキャプチャを作成し、コードをより自己文書化します。
後方参照
後方参照を使用すると、パターン内で以前にキャプチャされたのと同じテキストにマッチさせることができます:
\1、\2など — 番号でキャプチャグループを参照\k<name>— 名前付きグループを参照(構文は異なる)
例: \b(\w+)\s+\1\bは「the the」や「is is」のような繰り返された単語にマッチします。
例: (['"])(.*?)\1はシングルクォートとダブルクォートの両方の文字列にマッチし、閉じる引用符が開く引用符と一致することを保証します。
選択
パイプ文字|はOR演算子として機能します。グループと一緒に使用されることが多いです:
(cat|dog|bird)
これは「cat」、「dog」、または「bird」にマッチします。選択の順序に注意してください—正規表現エンジンは左から右に選択肢を試し、最初のマッチで停止します。
先読みと後読みアサーション
先読み・後読みアサーションは、前後にあるものに基づいて位置にマッチする幅ゼロのアサーションで、そのテキストをマッチに含めません。複雑なマッチングシナリオに非常に強力です。
先読みアサーション
先読みは現在の位置の後に何が来るかをチェックします:
(?=...)— 肯定先読み(...が続く必要がある)(?!...)— 否定先読み(...が続いてはいけない)
例: \d+(?= dollars)は「 dollars」が続く数字にマッチしますが、「 dollars」はマッチに含まれません。
例: ^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$は、少なくとも1つの大文字、1つの小文字、1つの数字を含み、8文字以上のパスワードを検証します。
後読みアサーション
後読みは現在の位置の前に何があるかをチェックします:
(?<=...)— 肯定後読み(...が先行する必要がある)(?<!...)— 否定後読み(...が先行してはいけない)
例: (?<=\$)\d+はドル記号が先行する数字にマッチしますが、ドル記号はマッチに含まれません。
例: (?<!un)happyは「happy」にマッチしますが、「unhappy」にはマッチしません。
プロのヒント: 先読み・後読みアサーションは、文字を消費せずに複数の条件をチェックする必要がある検証シナリオに最適です。コンテキストに基づいて何かにマッチさせる必要があるが、特定の部分だけを抽出したい場合にも不可欠です。
実践的な先読み・後読みの例
@記号なしでメールからドメインを抽出:
(?<=@)[a-zA-Z0-9.-]+
カンマが続かない単語にマッチ:
\b\w+\b(?!,)
マイナス記号が先行しない数字を見つける(正の数のみ):
(?<!-)\b\d+\b
一般的なパターンと実例
一般的な開発タスクのための実証済みの正規表現パターンを探りましょう。これらのパターンは本番環境で使用でき、実際のアプリケーションで遭遇するエッジケースを処理します。
メール検証
厳密さと実際の使用のバランスを取った実用的なメールパターン:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
このパターンは一般的なメール形式を許可しながら、明らかなエラーを防ぎます。RFC準拠の検証には、専用ライブラリの使用を検討してください—完全なRFC 5322正規表現は6,000文字を超えます。
URLマッチング
オプションのwww付きHTTP/HTTPS URLにマッチ:
https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)
ほとんどのURLをキャッチするシンプルなバージョン:
https?://[^\s]+
電話番号
柔軟な書式の米国電話番号:
^(\+1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$
これは次のような形式にマッチします:
- 123-456-7890
- (123) 456-7890
- +1 123 456 7890
- 1234567890
日付形式
ISO 8601日付形式(YYYY-MM-DD):
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
米国日付形式(MM/DD/YYYY):
^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$
IPアドレス
IPv4アドレス検証:
^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$
これは各オクテットが0から255の間であることを保証します。
クレジットカード番号
基本的なクレジットカード形式(オプションのスペースまたはダッシュ付き):
^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$
実際の検証にはLuhnアルゴリズムを使用することを忘れないでください—正規表現は形式のみをチェックします。
16進数カラー
オプションの#プレフィックス付き16進数カラーコードにマッチ:
^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$
これは6桁(#FF5733)と3桁(#F57)の両方の形式にマッチします。
ユーザー名検証
アンダースコアとハイフン付きの英数字ユーザー名、3〜16文字:
^[a-zA-Z0-9_-]{3,16}$
パスワード強度
少なくとも8文字、1つの大文字、1つの小文字、1つの数字、1つの特殊文字を要求:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&
;])[A-Za-z\d@$!%*?&]{8,}$
HTMLタグの削除
HTMLタグを削除(基本的な使用のみ、完全なHTMLパーサーではありません):
<[^>]+>
ファイルパス
Windowsファイルパス:
^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$
Unixファイルパス:
^(/[^/\0]+)+/?$
フラグと修飾子
フラグ(修飾子とも呼ばれる)は正規表現エンジンの動作を変更します。構文は言語によって異なりますが、一般的なフラグは次のとおりです:
i— 大文字小文字を区別しない(Insensitive)g— グローバル検索(最初のマッチだけでなくすべてのマッチを見つける)m— 複数行モード(^と$が各行の開始/終了にマッチ)s— ドット全体モード(.が改行にもマッチ)u— Unicode(完全なUnicodeマッチングを有効化)x— 拡張(空白とコメントを無視、可読性向上)
例(JavaScript):
/pattern/gi // 大文字小文字を区別せず、グローバル
/pattern/m // 複数行モード
/pattern/s // ドットが改行にマッチ
パフォーマンス最適化とベストプラクティス
正規表現は強力ですが、不適切に書かれると非常に遅くなる可能性があります。パフォーマンスとメンテナンス性のためのベストプラクティスを以下に示します。
破滅的バックトラッキングを避ける
ネストされた量指定子は指数関数的な時間複雑度を引き起こす可能性があります。次のようなパターンを避けてください:
(a+)+
(a*)*
(a+|b)+
これらは長い入力で正規表現エンジンをハングさせる可能性があります。代わりに、より具体的なパターンを使用するか、アトミックグループ(?>...)を使用してください(サポートされている場合)。
具体的であること
可能な限り具体的な文字クラスを使用してください:
- 良い:
[0-9]または\d - 悪い:
.(必要でない場合)
具体的なパターンはより速く、意図がより明確です。
アンカーを早期に使用
可能な場合は^と$でパターンを開始してください。これにより、正規表現エンジンが文字列全体をスキャンする必要がなくなります。
非キャプチャグループを優先
キャプチャが必要ない場合は、(?:...)を(...)の代わりに使用してください。わずかに高速で、メモリ使用量が少なくなります。
選択肢を賢く並べる
選択肢(|)を使用する場合、最も一般的なケースを最初に配置してください:
(jpg|jpeg|png|gif) //