正規表現リファレンス - パターンマッチングの基本から実践まで
正規表現(Regular Expression / regex)は、文字列のパターンマッチングに使われる表記法。検索・置換・バリデーションなど幅広い場面で利用される。
基本的なメタ文字
| メタ文字 | 意味 | 例 | マッチする文字列 |
|---|---|---|---|
. | 任意の1文字(改行以外) | a.c | abc, aXc, a1c |
\d | 数字 [0-9] | \d{3} | 123, 456 |
\D | 数字以外 | \D+ | abc, XYZ |
\w | 英数字とアンダースコア [a-zA-Z0-9_] | \w+ | hello_123 |
\W | \w以外 | \W | @, #, |
\s | 空白文字(スペース、タブ、改行等) | \s+ | , \t\n |
\S | 空白以外 | \S+ | hello |
\\ | バックスラッシュ自体をエスケープ | \\n | \n(リテラル) |
量指定子(Quantifiers)
パターンの繰り返し回数を指定する。
| 量指定子 | 意味 | 例 | マッチする文字列 |
|---|---|---|---|
* | 0回以上 | ab*c | ac, abc, abbc |
+ | 1回以上 | ab+c | abc, abbc(acは不可) |
? | 0回または1回 | colou?r | color, colour |
{n} | ちょうどn回 | \d{4} | 2026 |
{n,} | n回以上 | \d{2,} | 12, 123, 1234 |
{n,m} | n回以上m回以下 | \d{2,4} | 12, 123, 1234 |
貪欲マッチと最短マッチ
デフォルトの量指定子は**貪欲(greedy)で、できるだけ長くマッチする。?を付けると最短(lazy)**マッチになる。
対象文字列: <div>hello</div><div>world</div>
貪欲: <div>.*</div> → <div>hello</div><div>world</div>
最短: <div>.*?</div> → <div>hello</div>
| 貪欲 | 最短 | 意味 |
|---|---|---|
* | *? | 0回以上(最短) |
+ | +? | 1回以上(最短) |
? | ?? | 0回または1回(最短) |
{n,m} | {n,m}? | n〜m回(最短) |
アンカー(位置指定)
文字ではなく「位置」にマッチする。
| アンカー | 意味 | 例 | マッチ |
|---|---|---|---|
^ | 行頭 | ^Hello | 行頭のHello |
$ | 行末 | world$ | 行末のworld |
\b | 単語境界 | \bcat\b | cat(catchは不可) |
\B | 単語境界以外 | \Bcat | catchのcat部分 |
^と$はデフォルトでは文字列全体の先頭・末尾にマッチする。複数行モード(mフラグ)を有効にすると各行の先頭・末尾にマッチする。
文字クラス
[]で囲んで、マッチさせたい文字の集合を定義する。
[abc] # a, b, c のいずれか
[a-z] # 小文字アルファベット
[A-Z] # 大文字アルファベット
[0-9] # 数字(\d と同等)
[a-zA-Z0-9] # 英数字
[^abc] # a, b, c 以外(否定)
[^0-9] # 数字以外(\D と同等)
ハイフン-を文字としてマッチさせたい場合は、先頭か末尾に置くかエスケープする。
[-abc] # -, a, b, c のいずれか
[abc-] # a, b, c, - のいずれか
[a\-c] # a, -, c のいずれか
グループとキャプチャ
キャプチャグループ
()で囲むとグループ化され、マッチした部分を後から参照できる。
(\d{4})-(\d{2})-(\d{2})
2026-03-05に対して:
- グループ1:
2026 - グループ2:
03 - グループ3:
05
名前付きキャプチャグループ
(?<name>...) で名前を付けられる。
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
非キャプチャグループ
(?:...)はグループ化のみ行い、キャプチャしない。パフォーマンスが若干良い。
(?:https?|ftp)://[\w./]+
後方参照
キャプチャした内容を同じパターン内で再利用する。\1は最初のキャプチャグループを参照する。
(\w+)\s+\1 # 同じ単語の繰り返し("the the" 等)
選択(OR)
|でいずれかのパターンにマッチさせる。
cat|dog # "cat" または "dog"
(cat|dog) food # "cat food" または "dog food"
先読みと後読み(Lookaround)
マッチ位置の前後を条件として指定する。マッチ結果には含まれない(ゼロ幅アサーション)。
| 構文 | 名称 | 意味 |
|---|---|---|
(?=...) | 肯定先読み | 後ろに...が続く位置 |
(?!...) | 否定先読み | 後ろに...が続かない位置 |
(?<=...) | 肯定後読み | 前に...がある位置 |
(?<!...) | 否定後読み | 前に...がない位置 |
# 「円」が後に続く数字列
\d+(?=円)
# → "1000円" の "1000" にマッチ("円"は含まない)
# 「$」が前にない数字列
(?<!\$)\d+
# → "$100 200" の "200" にマッチ
# パスワードバリデーション(8文字以上、英字と数字を両方含む)
^(?=.*[a-zA-Z])(?=.*\d).{8,}$
フラグ(修飾子)
正規表現の動作を変更するオプション。言語によって指定方法が異なる。
| フラグ | 名称 | 効果 |
|---|---|---|
i | 大文字小文字無視 | Helloがhello,HELLO等にもマッチ |
g | グローバル | 最初の1つだけでなく全てのマッチを返す |
m | 複数行モード | ^と$が各行の先頭・末尾にマッチ |
s | ドットオール | .が改行にもマッチ |
u | Unicode | Unicode対応(\p{}が使える等) |
JavaScript での指定
const regex = /hello/gi
// または
const regex = new RegExp('hello', 'gi')
Python での指定
import re
re.findall(r'hello', text, re.IGNORECASE | re.MULTILINE)
実践パターン集
メールアドレス(簡易)
[\w.+-]+@[\w-]+\.[\w.]+
RFC準拠の完全なバリデーションは非常に複雑なため、実務では簡易パターン+ライブラリの併用が推奨される。
URL
https?://[\w!?/+\-_~;.,*&@#$%()'[\]]+
日本の電話番号
0\d{1,4}-\d{1,4}-\d{4}
郵便番号
\d{3}-\d{4}
日付(yyyy-mm-dd)
\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])
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)
HTMLタグの除去(置換用)
<[^>]+>
HTMLの解析には正規表現ではなくDOMパーサーを使うべきだが、簡易的なタグ除去には使える。
前後の空白を除去(トリム)
^\s+|\s+$
CSVの値を分割(ダブルクォート考慮)
"([^"]*(?:""[^"]*)*)"|([^,]+)
言語別の主なAPI
JavaScript
// テスト(マッチするか)
/\d+/.test('abc123') // true
// マッチ結果の取得
'abc123'.match(/\d+/) // ['123']
'abc123def456'.match(/\d+/g) // ['123', '456']
// 置換
'hello world'.replace(/world/, 'regex') // 'hello regex'
// 分割
'a,b,,c'.split(/,/) // ['a', 'b', '', 'c']
// 名前付きグループ
const m = '2026-03-05'.match(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/)
m.groups // { y: '2026', m: '03', d: '05' }
Python
import re
# テスト
re.search(r'\d+', 'abc123') # <re.Match object>
# 全マッチ
re.findall(r'\d+', 'abc123def456') # ['123', '456']
# 置換
re.sub(r'world', 'regex', 'hello world') # 'hello regex'
# 分割
re.split(r',', 'a,b,,c') # ['a', 'b', '', 'c']
# 名前付きグループ
m = re.match(r'(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})', '2026-03-05')
m.group('y') # '2026'
Pythonでは名前付きグループの構文が(?P<name>...)である点に注意(Pが必要)。
Java
import java.util.regex.*;
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("abc123def456");
// テスト
m.find() // true
// 全マッチ
while (m.find()) {
System.out.println(m.group()); // "123", "456"
}
// 置換
"hello world".replaceAll("world", "regex"); // "hello regex"
Javaではバックスラッシュを\\でエスケープする必要がある。
よくある落とし穴
貪欲マッチによる過剰マッチ
.*は改行以外の全てを最大限マッチするため、意図より広い範囲をマッチしやすい。最短マッチ.*?や否定文字クラス[^...]+を検討する。
エスケープ忘れ
.、*、+、?、(、)、[、]、{、}、|、^、$、\はメタ文字。リテラルとして使うにはエスケープが必要。
# IPアドレスの「.」はエスケープが必要
192\.168\.1\.1 # ✅ 正しい
192.168.1.1 # ❌ 任意の文字にマッチしてしまう
^と$の挙動
デフォルトでは文字列全体の先頭・末尾にマッチする。複数行テキストで各行を対象にするにはmフラグが必要。
バックトラッキングによる性能問題
ネストした量指定子(例: (a+)+)は指数関数的なバックトラッキングを引き起こし、処理が極端に遅くなる場合がある(ReDoS)。ユーザー入力に対して正規表現を使う場合は特に注意が必要。
# 危険なパターン(ReDoS)
(a+)+$
# 安全な書き換え
a+$