Java 逆引き集 | 文字列の正規表現(Pattern / Matcher) — テキスト検証

Java Java
スポンサーリンク

文字列の正規表現(Pattern / Matcher) — テキスト検証

正規表現は「文字列がルールに合っているか」「欲しい部分だけ抜き出す」ための強力な道具。Javaでは java.util.regexPatternMatcher が中核です。パターンをコンパイルして、対象文字列とマッチングするのが基本の流れです。


基本の流れと役割

  • 役割の分離:
    • Pattern: 正規表現の「ルール」をコンパイルして保持する。繰り返し使う場合は一度コンパイルして再利用すると効率的。
    • Matcher: コンパイル済みパターンと対象文字列を組み合わせ、照合・検索・抽出を行う。
import java.util.regex.*;

Pattern p = Pattern.compile("[A-Za-z0-9_]+"); // 英数字+アンダースコア
Matcher m = p.matcher("user_123");
boolean ok = m.matches(); // 文字列全体がルールに一致?
System.out.println(ok); // true
Java

Tip: 繰り返し使うパターンは、毎回 compile せずに再利用すると速い。


matches / find / lookingAt の違い(ここが最重要)

  • matches(): 文字列「全体」がパターンに一致するかを判定。入力検証(メール・日付など)に最適。
  • find(): 文字列の「一部」に一致する箇所を順次見つける。ログ解析や抽出に向く。
  • lookingAt(): 文字列の「先頭から」一致するか(全体一致ではない)。先頭固定のトークンチェックに使う。
var s = "ID=abc123; more...";
var p = Pattern.compile("[a-z0-9]+");

// 全体一致(false)
System.out.println(p.matcher(s).matches());

// 先頭から一致(false:先頭は 'I')
System.out.println(p.matcher(s).lookingAt());

// 部分一致(true:'abc123' を見つける)
Matcher m = p.matcher(s);
if (m.find()) System.out.println(m.group()); // abc123
Java

これを混同すると「なぜ合わない?」が起きがち。入力検証なら matches、抽出なら find を使うのが定石です。


文字列のエスケープ(“二重バックスラッシュ”の罠)

Javaの文字列リテラルは「バックスラッシュでエスケープ」されるので、正規表現で \d(数字)や \s(空白)を書きたい場合は、Java文字列では \\d\\s と「2つ」必要です。

// 数字だけ(1文字以上)
Pattern p = Pattern.compile("\\d+"); // 正規表現の \d をJava文字列で表すと \\d
System.out.println(p.matcher("123").matches()); // true
System.out.println(p.matcher("12a").matches()); // false
Java

覚え方: 「正規表現のバックスラッシュ」×「Java文字列のバックスラッシュ」= 2重に必要。


代表的な検証・抽出パターン

  • 半角数字のみ:
Pattern.compile("\\d+"); // 1文字以上の数字  [株式会社ドライブライン](https://driveline.jp/media/programming-38/)
Java
  • ID(半角英数字+アンダースコア):
Pattern.compile("[A-Za-z0-9_]+"); // 1文字以上  [株式会社ドライブライン](https://driveline.jp/media/programming-38/)
Java
  • 日付 yyyy-MM-dd(ざっくり):
Pattern.compile("\\d{4}-\\d{2}-\\d{2}"); // 年-月-日  [株式会社ドライブライン](https://driveline.jp/media/programming-38/)
Java
  • 簡易メール形式(最低限):
Pattern.compile("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"); // ドメイン末尾2文字以上  [株式会社ドライブライン](https://driveline.jp/media/programming-38/)
Java

実務では「完全なメール検証」は過剰になりがち。形式の最低限チェックに留め、ドメイン照会などは別手段で行うのが現実的です。


グループと抽出(find + group)

  • グループ: 丸括弧 (...) で「取り出したい部分」をキャプチャ。group(0) は全体一致、group(1) 以降が各グループ。
  • find ループ: 複数箇所を順番に抽出できる。
var log = "user=alice id=42; user=bob id=7";

// user と id をセットで抜き出す
Pattern p = Pattern.compile("user=([a-z]+)\\s+id=(\\d+)");
Matcher m = p.matcher(log);
while (m.find()) {
    String user = m.group(1);  // 1番目のグループ
    String id   = m.group(2);  // 2番目のグループ
    System.out.println(user + " -> " + id);
}
Java

matches と find の違い、そして group での抽出が使いこなしの鍵です。


フラグとオプション(大文字小文字無視・複数行など)

  • 大文字小文字無視: Pattern.CASE_INSENSITIVE
  • 複数行モード: Pattern.MULTILINE(^ と $ が行単位で機能)
  • ドットで改行も含める: Pattern.DOTALL
Pattern p = Pattern.compile("^error: (.+)$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
Matcher m = p.matcher("Error: first line\nINFO: ok\nerror: second");
while (m.find()) System.out.println(m.group(1));
Java

用途に応じてフラグを組み合わせると、意図通りにマッチングしやすくなります。


実務のパフォーマンスと安全性の注意点

  • パターンは再利用: 頻繁に使う場合、毎回 compile せずにキャッシュ・再利用すると速い(コンパイルコスト削減)。
  • コメントモード活用: 複雑なパターンは「見通し」を優先。Pattern.COMMENTS でスペースや # コメントを許可すると保守性が上がる。
  • ReDoSに注意: 一部の正規表現は最悪ケースで爆発的に遅くなる(バックトラッキング過多)。入力サイズやパターン設計に注意し、アンカー使用・曖昧な量指定の抑制などで被害を避ける。

例題で身につける

例題1: 入力検証(郵便番号 123-4567)

var p = Pattern.compile("\\d{3}-\\d{4}");
System.out.println(p.matcher("135-0063").matches()); // true
System.out.println(p.matcher("1350063").matches());  // false
Java

検証は「全体一致」の matches() を使うのが基本です。

例題2: ログからIPを抽出

var log = "from 192.168.1.2 to 10.0.0.5; bad 999.999.999.999";
var ip = Pattern.compile("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b"); // 簡易版
var m = ip.matcher(log);
while (m.find()) System.out.println(m.group());
Java

抽出は find() の反復で「部分一致」を順に拾います。

例題3: 大文字小文字を無視してタグ抽出

var html = "<Title>Hello</title><TITLE>World</TITLE>";
var p = Pattern.compile("<title>(.*?)</title>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
var m = p.matcher(html);
while (m.find()) System.out.println(m.group(1)); // Hello / World
Java

CASE_INSENSITIVEDOTALL の組み合わせで、タグや改行をまたぐ抽出が楽になります。


すぐ使えるテンプレート

  • 全体一致の検証(メール・日付など)
boolean valid = Pattern.compile("正規表現").matcher(input).matches();
Java
  • 部分一致の抽出(複数拾う)
Matcher m = Pattern.compile("(...)(...)").matcher(text);
while (m.find()) {
    String g1 = m.group(1);
    String g2 = m.group(2);
}
Java
  • パターン再利用(効率化)
final Pattern P_NUM = Pattern.compile("\\d+"); // static final でキャッシュ  [株式会社ドライブライン](https://driveline.jp/media/programming-38/)
Java
  • フラグ指定
Pattern p = Pattern.compile("...", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
Java

まとめ

  • Pattern がルール、Matcher が照合役。使い分けは matches(全体)・find(部分)・lookingAt(先頭)
  • Java文字列のエスケープを忘れない(\d, \s などは二重バックスラッシュ)
  • 実務ではパターン再利用・コメントモード・ReDoS対策で「速く安全に」

タイトルとURLをコピーしました