14

MySql 5.1 に保存しているテキストにサロゲート文字が含まれる状況に直面しています。これでは UTF-16 がサポートされていないため、データベースに保存する前に、これらのサロゲート ペアを Java メソッドで手動で削除したいと考えています。

私は今のところ次の方法を書いていますが、これを処理するための直接的で最適な方法があるかどうか知りたいです.

よろしくお願いします。

public static String removeSurrogates(String query) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < query.length() - 1; i++) {
        char firstChar = query.charAt(i);
        char nextChar = query.charAt(i+1);
        if (Character.isSurrogatePair(firstChar, nextChar) == false) {
            sb.append(firstChar);
        } else {
            i++;
        }
    }
    if (Character.isHighSurrogate(query.charAt(query.length() - 1)) == false
            && Character.isLowSurrogate(query.charAt(query.length() - 1)) == false) {
        sb.append(query.charAt(query.length() - 1));
    }

    return sb.toString();
}
4

5 に答える 5

8

Java 文字列は 16 ビット文字のシーケンスとして格納されますが、それらが表すのは Unicode 文字のシーケンスです。Unicode 用語では、それらはコード単位として格納されますが、モデル コード ポイントです。したがって、文字/コードポイント表現に存在しないサロゲートを削除することについて話すのは、やや無意味です (ただし、不正な単一のサロゲートがある場合を除きます。その場合、他の問題があります)。

むしろ、エンコード時にサロゲートが必要な文字を削除する必要があります。これは、基本的な多言語面を超えた文字を意味します。単純な正規表現でそれを行うことができます:

return query.replaceAll("[^\u0000-\uffff]", "");
于 2012-10-12T23:13:13.707 に答える
8

ここにいくつかのことがあります:

  • Character.isSurrogate(char c):

    char 値は、低サロゲート コード単位または高サロゲート コード単位のいずれかである場合にのみ、サロゲート コード単位です。

  • ペアのチェックは無意味に思えます。すべてのサロゲートを削除してみませんか?

  • x == falseと同等です!x

  • StringBuilder同期が必要ない場合 (ローカル スコープを離れることのない変数など) には、この方が適しています。

私はこれを提案します:

public static String removeSurrogates(String query) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < query.length(); i++) {
        char c = query.charAt(i);
        // !isSurrogate(c) in Java 7
        if (!(Character.isHighSurrogate(c) || Character.isLowSurrogate(c))) {
            sb.append(firstChar);
        }
    }
    return sb.toString();
}

ifステートメントの分解

あなたはこの声明について尋ねました:

if (!(Character.isHighSurrogate(c) || Character.isLowSurrogate(c))) {
    sb.append(firstChar);
}

これを理解する 1 つの方法は、各操作を独自の関数に分割することです。これにより、組み合わせが期待どおりに機能することがわかります。

static boolean isSurrogate(char c) {
    return Character.isHighSurrogate(c) || Character.isLowSurrogate(c);
}

static boolean isNotSurrogate(char c) {
    return !isSurrogate(c);
}

...

if (isNotSurrogate(c)) {
    sb.append(firstChar);
}
于 2012-10-12T21:08:46.660 に答える
2

なぜ単純に

for (int i = 0; i < query.length(); i++) 
    char c = query.charAt(i);
    if(!isHighSurrogate(c) && !isLowSurrogate(c))
        sb.append(c);

それらを完全に消去するのではなく、おそらく「?」に置き換える必要があります。

于 2012-10-12T21:07:22.970 に答える
1

ちょっと興味があるんだけど。charが高いサロゲートである場合、次のサロゲートをチェックする必要がありますか?それは低い代理であると思われます。変更されたバージョンは次のようになります。

public static String removeSurrogates(String query) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < query.length(); i++) {
        char ch = query.charAt(i);
        if (Character.isHighSurrogate(ch))
            i++;//skip the next char is it's supposed to be low surrogate
        else
            sb.append(ch);
    }    
    return sb.toString();
}
于 2013-01-23T11:26:21.233 に答える