Java
 Computer >> コンピューター >  >> プログラミング >> Java

【Java入門】Pattern.CANON_EQフラグの使い方をサンプルコードで解説

JavaのPatternクラスには、正規表現のマッチング動作を制御するためのさまざまなフラグが用意されています。そのひとつであるCANON_EQフィールドは、「正規化等価(canonical equivalence)」に基づいて文字を照合するためのフラグです。

このフラグをcompile()メソッドに指定すると、2つの文字は完全な正準分解(canonical decomposition)の結果が等しい場合に限りマッチするとみなされます。

ここでいう正準分解とは、Unicodeのテキスト正規化形式のひとつです。たとえば、アクセント記号付きの合成済み文字(1つのコードポイント)と、基本文字+結合文字(複数のコードポイント)の組み合わせは、見た目が同じでも内部的な表現が異なることがあります。CANON_EQを使えば、こうした表現の違いを吸収してマッチングできます。

例1:合成済み文字とのマッチング

次の例では、パターン「b + 結合文字U+0307(ドット)」に対して、合成済み文字「ḃ(U+1E03)」がマッチするかどうかを確認しています。

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

public class CANON_EQ_Example {
    public static void main(String args[]) {
        String regex = "b\u0307"; // b + 結合文字(ドット)
        // 正規表現をコンパイル(CANON_EQフラグを指定)
        Pattern pattern = Pattern.compile(regex, Pattern.CANON_EQ);
        // Matcherオブジェクトを取得
        Matcher matcher = pattern.matcher("\u1E03"); // 合成済み文字 ḃ
        if (matcher.matches()) {
            System.out.println("Match found");
        } else {
            System.out.println("Match not found");
        }
    }
}

実行結果

Match found

CANON_EQフラグを有効にしているため、「b + U+0307」という分解表現と「U+1E03」という合成済み文字が正規化等価として扱われ、マッチが成功します。フラグなしの場合は、この2つは異なる文字列として扱われ、マッチしません。

例2:複数の入力パターンでの検証

次の例では、パターン「a + 結合文字U+030A(リング)」に対して、複数の文字列を順番に照合しています。

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

public class CANON_EQ_Example {
    public static void main(String args[]) {
        String regex = "a\u030A"; // a + 結合文字(リング)
        // 正規表現をコンパイル(CANON_EQフラグを指定)
        Pattern pattern = Pattern.compile(regex, Pattern.CANON_EQ);
        // 検証対象の文字列配列
        String[] input = {"\u00E5", "a\u0311", "a\u0325", "a\u030A", "a\u1E03", "a\uFB03"};
        for (String ele : input) {
            Matcher matcher = pattern.matcher(ele);
            if (matcher.matches()) {
                System.out.println(ele + " is a match for " + regex);
            } else {
                System.out.println(ele + " is not a match for " + regex);
            }
        }
    }
}

実行結果

å(\u00E5)is a match for a\u030A
a\u0311 is not a match for a\u030A
a\u0325 is not a match for a\u030A
a\u030A is a match for a\u030A
a\u1E03 is not a match for a\u030A
a\uFB03 is not a match for a\u030A

結果の解説

  • \u00E5(å):合成済みの「a + リング」であり、正準分解すると「a + U+030A」になるためマッチします。
  • a\u030A:パターンと完全に同じ表現なのでマッチします。
  • a\u0311(キャロン)・a\u0325(下付きリング):結合文字が異なるため、正準分解の結果も異なりマッチしません
  • a\u1E03(下付きドット付きa):別の結合文字を含むためマッチしません
  • a\uFB03(合字ffi):「f + f + i」に分解されますが、これは互換分解(compatibility decomposition)であり正準分解とは異なるためマッチしません

まとめ

Pattern.CANON_EQを使用すると、Unicodeの正規化等価性に基づいた柔軟な文字列マッチングが可能になります。特に、ユーザー入力など同じ見た目の文字が異なる内部表現を持つ可能性があるデータを扱う場合に有効です。ただし、処理コストが増加する点や、互換分解まで吸収したい場合は事前にjava.text.Normalizerで正規化する方法も検討するとよいでしょう。

  1. Java PatternクラスのDOTALLフィールドとは?具体例でわかりやすく解説

    Javaの Pattern クラスには、正規表現の動作を制御するためのさまざまなフラグが用意されています。そのひとつである DOTALL フィールドを有効にすると、いわゆる「dotallモード」がオンになります。デフォルトの状態では、正規表現の「.」(ドット)というメタ文字は、改行などの行末記号を除くすべての文字に一致します。しかし、DOTALLモードを有効にすると、「.」は行末記号も含めたすべての文字に一致するようになります。例1:通常モードでの「.」の挙動まず、フラグを指定せずにパターンをコンパイルした場合の動作を見てみましょう。import java.util.regex.Matcher

  2. JavaのPattern.COMMENTSフィールドとは?使い方を実例付きで解説

    JavaのPatternクラスが持つCOMMENTSフィールドは、正規表現パターンの中に空白文字やコメントを自由に記述できるようにするフラグです。このフラグをcompile()メソッドの第2引数として指定すると、パターン内の空白文字や、#記号で始まるコメント部分はすべて無視されてコンパイルされます。 複雑な正規表現を扱う場合、そのままでは読みにくくなりがちですが、COMMENTSフラグを活用すれば、各部分に説明用のコメントを付けたり、改行やインデントを使って整形したりできるため、可読性と保守性が大きく向上します。なお、このフラグは正規表現内に(?x)を埋め込む方法でも同等の効果が得られます。