1. 導入:なぜMatcherのメソッドを区別する必要があるのか
Javaで文字列操作を行う際、正規表現は非常に強力なツールです。しかし、PatternクラスとMatcherクラスを扱う際、matches()、find()、lookingAt()の違いを曖昧に理解していると、バグの温床になりがちです。特に「文字列の一部だけを抽出したいのか」「全体が形式に適合しているか確認したいのか」という意図を明確に使い分けることが、堅牢なシステム開発において不可欠です。本記事では、これら3つのメソッドの使い分けと、実務で役立つ名前付きグループの活用法を解説します。
2. 基礎知識:3つのメソッドの挙動の違い
これら3つのメソッドは、いずれも正規表現エンジンを起動しますが、検証範囲が異なります。
matches(): 文字列全体が正規表現と完全に一致する場合のみtrueを返します。入力データのバリデーション(形式チェック)に最適です。
find(): 文字列の中に正規表現に一致するサブシーケンスがあるかを探します。文章中から特定のパターンを抽出する際に使います。
lookingAt(): 文字列の「先頭」が正規表現に一致するかを判定します。全体一致は求めませんが、先頭からマッチしなければfalseとなります。
3. 実装とサンプルプログラム
以下のコードでは、これら3つのメソッドの挙動と、実務で可読性を高める「名前付きグループ」の使用例を示しています。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExample {
public static void main(String[] args) {
// 名前付きグループを使用して日付形式を定義
String regex = "(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})";
Pattern pattern = Pattern.compile(regex);
String input = "2023-10-27 is the date.";
// 1. matches(): 全体一致が必要なため、この場合はfalseになる
Matcher m1 = pattern.matcher(input);
System.out.println("matches: " + m1.matches());
// 2. find(): 途中にマッチする箇所があるためtrue
Matcher m2 = pattern.matcher(input);
if (m2.find()) {
// 名前付きグループで値を取得(可読性が高い)
System.out.println("find: 年=" + m2.group("year") + ", 月=" + m2.group("month"));
}
// 3. lookingAt(): 先頭がマッチするためtrue
Matcher m3 = pattern.matcher(input);
System.out.println("lookingAt: " + m3.lookingAt());
}
}
4. 応用・注意点:現場での落とし穴
・状態の保持に注意
Matcherは「状態」を持っています。find()を繰り返すことで、次のマッチ箇所へと移動します。ループ内で使用する際は、意図せず次の検索に進んでいないか注意が必要です。
・名前付きグループの活用
Java 7以降、正規表現内で (?<name>…) という構文を用いることで、インデックス(group(1)など)ではなく名前(group(“name”))で結果を取得できます。これにより、正規表現の構造が変わってもJava側のコード修正コストを最小限に抑えられます。
・パフォーマンスへの配慮
Patternのコンパイル(Pattern.compile)は高コストな処理です。ループ内で毎回コンパイルせず、static finalフィールドとして定義するか、キャッシュ機構を利用して再利用することを強く推奨します。
これらのメソッドを適切に使い分けることで、バリデーションロジックやログ解析処理の精度を一段階引き上げることができるでしょう。

コメント