【Java学習|豆知識】Java正規表現の隠し技!「肯定の先読み (?=X)」で文字列解析をスマートに

導入

皆さんは、正規表現で「ある特定の文字列に続くパターンだけを抽出したい」と悩んだことはありませんか?通常の正規表現ではマッチした文字を消費(消費=マッチ範囲として確定させること)してしまいますが、肯定の先読み(Positive Lookahead)を使えば、文字を消費せずに条件判定だけを行うことができます。これにより、複雑な条件分岐をコード内で書く必要がなくなり、正規表現だけでスマートに抽出処理が完結します。

基礎知識

Javaの正規表現エンジン(java.util.regex.Pattern)において、(?=X)という構文は「現在の位置の直後にXが続くか」を判定します。
重要なポイントは「マッチした結果にはXは含まれない」ということです。例えば、`A(?=B)`という正規表現を`AB`という文字列に適用すると、マッチするのは`A`だけです。`B`は「先読み」の条件として使われるだけで、マッチ範囲には入りません。この「消費しない」という特性が、重複するパターンや複雑な条件の抽出において非常に強力な武器となります。

実装/解決策

Javaでこの機能を使う際は、`Pattern`クラスと`Matcher`クラスを組み合わせます。特に、マッチした部分を後から再利用したい場合は、名前付きグループ(Named groups)を組み合わせると非常に可読性が高まります。
例えば、「数字の後に特定のキーワードが続く場合のみ数字を抜き出す」といった処理を、一行の正規表現で実現可能です。

サンプルプログラム

以下のコードは、文字列の中から「円」という文字が直後に続く数字だけを抽出する例です。

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

public class LookaheadExample {
    public static void main(String[] args) {
        // 「円」という文字が続く数字にマッチする正規表現
        // (?=円) が肯定の先読み。数字は消費するが、「円」は消費しない
        String regex = "(?<price>\\d+)(?=円)";
        String input = "定価1000円、セール価格800円、または100ドル";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        System.out.println("抽出された価格:");
        while (matcher.find()) {
            // 名前付きグループ「price」で取得
            String price = matcher.group("price");
            System.out.println(price + "円");
        }
    }
}

応用・注意点

現場での開発で注意すべき点が2つあります。
1つ目はパフォーマンスです。先読みは強力ですが、複雑なネストや長い文字列に対して多用するとバックトラック(一致しない場合に何度も戻って再試行すること)が発生し、処理速度が低下することがあります。
2つ目はマッチ範囲の誤解です。先読みの内容((?=X)の中身)は、`matcher.group()`で取得することはできません。あくまで「条件判定」であることを忘れないでください。
もし「円」も含めて取得したい場合は、肯定の先読みを使わずに通常のグループ化を行うか、先読みの外側にもう一つグループを作るなど、要件に合わせて設計を見直しましょう。このTipsを使いこなせれば、複雑な文字列解析ロジックが驚くほどスッキリしますよ。

コメント

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