【Java学習|豆知識】Java正規表現の落とし穴を回避する!Pattern.LITERALの活用術

導入

Javaで正規表現を扱う際、意図せずメタ文字(.や、?など)が特殊な意味を持ってしまい、バグを引き起こした経験はありませんか?例えば、ユーザー入力された検索文字列に「.」が含まれていると、正規表現としては「任意の1文字」と解釈されてしまいます。このような「文字列をそのままの文字として扱いたい」という課題をスマートに解決するのが、Pattern.LITERALフラグです。

基礎知識

Javaの正規表現はjava.util.regex.Patternクラスでコンパイルされます。通常、正規表現エンジンは「.」を「任意の文字」というメタ文字として解釈しますが、Pattern.compileメソッドにフラグを指定することで、この振る舞いを制御できます。
Pattern.LITERALを有効にすると、正規表現エンジンはメタ文字を「文字通りの記号」として扱うようになります。これにより、特殊文字をエスケープ(\\Q…\\E)する手間を省き、安全に比較や検索を行えるようになります。

実装/解決策

実装は非常にシンプルです。Pattern.compileの第2引数にPattern.LITERALを指定するだけです。これにより、対象のパターン全体がリテラル文字列として扱われるようになります。もし動的に取得した文字列を安全にマッチングさせたい場合は、このフラグを使用するのがベストプラクティスです。

サンプルプログラム

以下のコードでは、メタ文字を含む文字列をそのままリテラルとして検索する例を示します。

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

public class LiteralExample {
    public static void main(String[] args) {
        // 検索対象のテキスト
        String text = "価格は100.00ドルです。";
        // 検索したいキーワード(「.」が含まれている)
        String keyword = "100.00";

        // 通常の正規表現としてコンパイルすると「.」がワイルドカードになり意図しない結果になる可能性がある
        // そこでPattern.LITERALを指定してリテラルとして扱う
        Pattern pattern = Pattern.compile(keyword, Pattern.LITERAL);
        Matcher matcher = pattern.matcher(text);

        if (matcher.find()) {
            System.out.println("キーワードが見つかりました: " + matcher.group());
        } else {
            System.out.println("見つかりませんでした。");
        }
    }
}

応用・注意点

注意点1:フラグの範囲
Pattern.LITERALを指定すると、そのPatternオブジェクト全体がリテラル扱いになります。そのため、一部だけ正規表現を使い、一部だけリテラルにしたいといった混在はできません。

注意点2:Pattern.quoteとの使い分け
似た機能にPattern.quote(String s)という静的メソッドがあります。これは引数の文字列を\\Q…\\Eで囲んで返却するものです。特定のキーワードだけをリテラル化したい場合はPattern.quoteが手軽ですが、プログラム全体でフラグ管理を統一したい場合は、Pattern.LITERALを用いるとコードの可読性が向上します。

現場では、ユーザーから渡される入力値を扱う際、安易に正規表現として結合せず、必ずリテラルとして扱うかエスケープ処理を行うことを徹底してください。これがセキュリティと品質を守る第一歩です。

コメント

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