導入
Javaで正規表現を扱う際、PatternクラスとMatcherクラスは避けて通れません。しかし、多くのエンジニアが「なぜかマッチしない」「一部だけ抽出したいのに失敗する」といった挙動に悩まされます。その原因の多くは、Matcher.matches()メソッドの仕様に対する誤解にあります。本記事では、実務で頻出する「領域全体の一致判定」と、より柔軟なマッチングを行うための使い分けについて解説します。
基礎知識
Javaの正規表現エンジンでは、主に以下の2つのメソッドがマッチングの成否を判定します。
Matcher.matches(): 対象の文字列全体が、正規表現パターンと完全に一致しているかを判定します。文字列の先頭から末尾まで、すべてがパターンに合致しなければfalseを返します。
Matcher.find(): 対象の文字列の中で、指定したパターンに部分的に一致する箇所があるかを探します。
実務においては、バリデーション(入力値チェック)にはmatches()、ログ解析やテキスト抽出にはfind()と使い分けるのが定石です。
実装/解決策
「文字列の特定のパターンを抽出したいのにmatches()を使ってしまう」というのが最も典型的なバグです。例えば、”ID:12345″ という文字列から数値部分だけを抽出したい場合、正規表現「\d+」をmatches()に渡すと、文字列全体(ID:が含まれているため)と合致しないため失敗します。
解決策として、抽出を行いたい場合はfind()を使用し、さらにグループ化(括弧)を活用して特定箇所を取り出す手法が推奨されます。
サンプルプログラム
以下のコードは、実務でよくある「特定のフォーマットの文字列から値を抽出する」例です。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExample {
public static void main(String[] args) {
String input = "Order-ID:998877";
// 名前付きグループを使用してID部分を抽出するパターン
// (?...) でグループに名前を付けると後から参照しやすいです
String regex = "Order-ID:(?\\d+)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
// matches()ではなくfind()を使うことで、全体の一致ではなく部分一致を探す
if (matcher.find()) {
// グループ名を指定して抽出
String orderId = matcher.group("id");
System.out.println("抽出されたID: " + orderId);
} else {
System.out.println("パターンに一致しませんでした。");
}
}
}
応用・注意点
実務でさらに一歩進んだ実装をする際の注意点を挙げます。
1. Patternの再利用:
Patternオブジェクトの生成はコストがかかります。ループ内で何度も同じ正規表現を使う場合は、static finalフィールドとして定義するか、キャッシュ機構を利用してください。
2. 正規表現の複雑化:
Named groups(名前付きグループ)を使うと、コードの可読性が劇的に向上します。インデックス(group(1)など)で指定すると、正規表現を変更した際に修正漏れが発生しやすいため、可能な限り名前を活用しましょう。
3. バリデーション時の注意:
ユーザー入力のバリデーションにmatches()を使う場合、意図せず「改行コード」が含まれていないか注意が必要です。必要に応じてPattern.DOTALLフラグなどを検討してください。
適切なメソッド選択とグループ活用で、堅牢な文字列処理を実装しましょう。

コメント