【Java学習|豆知識】Matcher.usePatternで実現する、正規表現パターンの動的切り替え術

導入

Javaで文字列の解析を行う際、通常は「パターンをコンパイルしてMatcherを作成し、使い終わったら破棄する」という流れが一般的です。しかし、大量の文字列に対して、処理の途中で動的に検索条件を切り替えたいケースはありませんか?毎回Matcherを再生成するのはメモリやGCの観点から非効率です。ここで役立つのが Matcher.usePattern(Pattern) メソッドです。このメソッドを使えば、既存のMatcherオブジェクトを再利用しながら、内部の正規表現だけを差し替えることが可能になります。

基礎知識

Javaの正規表現エンジンは、主に Pattern クラスと Matcher クラスで構成されます。
Pattern: コンパイルされた正規表現を表します。
Matcher: 文字列に対してマッチング操作を行うエンジンです。
通常、Matcherは「どのパターンで、どの文字列を走査するか」という情報を保持しています。usePattern を呼び出すと、Matcherが保持している現在のパターンを破棄し、新しいパターンに置き換えます。その際、マッチ対象の文字列(CharSequence)は維持されるため、効率的な順次処理が可能です。

実装/解決策

手順は非常にシンプルです。
1. 最初に適当なパターンでMatcherを生成します。
2. 処理中に条件を変更したいタイミングで、新しくコンパイルしたPatternを usePattern に渡します。
3. これにより、同じMatcherインスタンスを使って、異なる正規表現で対象文字列を再評価できます。
なお、名前付きグループ(Named groups)を活用すれば、パターンが変わっても「グループ名」で値を抽出するロジックを共通化でき、コードの可読性が大幅に向上します。

サンプルプログラム

以下のコードは、一つのMatcherを使い回し、異なるパターンでログ文字列から情報を抽出する例です。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MatcherExample {
    public static void main(String[] args) {
        String input = "User:admin, IP:192.168.1.1";
        
        // 1. 最初のパターン(名前付きグループを使用)
        Pattern p1 = Pattern.compile("User:(?<name>\\w+)");
        Matcher matcher = p1.matcher(input);
        
        if (matcher.find()) {
            System.out.println("名前: " + matcher.group("name"));
        }
        
        // 2. 同じMatcherインスタンスでパターンを動的に変更
        Pattern p2 = Pattern.compile("IP:(?<address>[\\d.]+)");
        matcher.usePattern(p2);
        
        // パターン変更後はマッチングをリセットする必要があるため、再度findを呼ぶ
        if (matcher.find()) {
            System.out.println("IPアドレス: " + matcher.group("address"));
        }
    }
}

応用・注意点

usePattern を使用する際の最大の注意点は、マッチング状態がリセットされることです。
リセットの挙動: usePatternを呼び出すと、内部の検索位置(インデックス)やマッチ結果がクリアされます。そのため、同じ文字列に対して続けてマッチングを行いたい場合は、必ず再度 find()matches() を呼び出す必要があります。
パフォーマンス: パターンを何度もコンパイルするのはコストがかかります。頻繁に切り替えるパターンが決まっている場合は、あらかじめ Patternオブジェクトをキャッシュ(Mapなどで保持)しておくことを強く推奨します。
名前付きグループの互換性: 切り替える先のパターンに、以前のパターンで指定していたグループ名が存在しない場合、group(“name”)を呼び出すと IllegalArgumentException が発生します。パターン変更時には、期待するグループ名が確実に存在するか確認する設計を心がけてください。

コメント

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