9

文字または数字以外の文字を削除して文字列を除外するプログラムがあります。このプログラムは、中国語、ロシア語、アラビア語などを含む多数の言語をサポートしています。プログラムは次のとおりです。

StringBuilder strBuilder = new StringBuilder();

for (int i = 0; i < src.length(); i++) {
    int ch = src.codePointAt(i);
    if (Character.isLetterOrDigit(ch)) {
        strBuilder.appendCodePoint(ch);
    }
}

メソッドを使用codePointAtして、上位サロゲートと下位サロゲートを介して UTF 32 ビットで表現される文字をサポートします。フィルタリングを実行する前に、各文字列を正規化する必要があるかどうかを知る必要がありますか? Normalizer.normalizeループを実行する前にメソッドを呼び出すことを指しています。はいの場合、どちらNormalizer.Formを使用すればよいですか?

ありがとう。

4

2 に答える 2

4

それはすべて、アルゴリズムを実際にどのように動作させたいかによって異なります。

例として、文字列(u+0061&nbsp;sᴍᴀʟʟʟᴇᴛᴛᴇʀᴀᴀ、続いてu+0308ᴄᴏᴍʙɪɴɪɴɢ&nbsp;ᴅɪᴀᴇʀᴇsɪs)を考えてみ"a\u0308"ましょう。標準的に同等であるということは、アルゴリズムがこれら 2 つを区別してはならないことを意味します。正準的に同等の文字列を同じように動作させる簡単な方法の 1 つは、2 つを同じ正準正規化形式 (NFC または NFD) に正規化することです。"ä""\u00e4"

これらの文字列が表すものによっては、代わりに同等の互換性 (NFKC または NFKD) を使用することができます。これは通常、識別子などに推奨されます。これら 2 つは、互換性のある文字を推奨される同等の文字に変換します (U+2126 ᴏʜᴍ sɪɢɴ を U+03A9 ɢʀᴇᴇᴋ ᴄᴀᴘɪᴛᴀʟ ʟᴇᴛᴛᴇʀ ᴏᴍᴇɢᴀ に変換する、または合字文字をそれらが構成する一連の文字に変換するなど)。

必要な同等性の種類に関係なく、原則は変わりません。同等の文字列を同等に扱いたい場合は、両方を正規化するのが最も簡単な方法です。

すべての同等の文字列で同じ動作が得られたら、別の問題を考慮する必要があります。「文字でも数字でもない文字」をすべて破棄する場合、文字を含む文字列と結合するとどうなりますか(U+092C ᴅᴇᴠᴀɴᴀɢᴀʀɪ "\u092C\u093F"ʟᴇᴛᴛᴇʀ ʙᴀ の後に U+093F ᴅᴇᴠᴀɴᴀɢᴀʀɪ ᴠᴏᴡᴇʟ sɪɢɴ ɪ) のような記号は、बि のように見えます。これらは 2 つの別個のコードポイントであり、U+093F は文字ではありません。これら 2 つは、どの正規化形式でも作成されません。結合記号を削除 (ब のまま) しますか?

それらをドロップしても問題ない場合は、現在のアルゴリズムを使用できます。それ以外の場合は、大まかに言えば、一連の基本文字の後に結合記号が続く書記素クラスターを反復処理する必要があります。JavaICUの両方が、書記素クラスターを見つけるための API を提供します (Java はこれらを「文字区切り」と呼びます)。

于 2013-03-07T17:28:58.117 に答える
0

コードポイントを反復するためのコードは完全に正しくないことに注意してください。

for(int cp, i = 0; i < s.length(); i += Character.charCount(cp)) {
    cp = s.codePointAt(i);
    // Process cp...
}

申し訳ありませんが、正規化する必要があるかどうかはわかりません。

于 2013-03-07T15:15:47.017 に答える