導入
皆さんは、正規表現で「ある特定の文字列に続くパターンだけを抽出したい」と悩んだことはありませんか?通常の正規表現ではマッチした文字を消費(消費=マッチ範囲として確定させること)してしまいますが、肯定の先読み(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を使いこなせれば、複雑な文字列解析ロジックが驚くほどスッキリしますよ。

コメント