web-dev-qa-db-ja.com

UTF-8文字列に不正にエンコードされた文字が含まれているかどうかを検証する方法

大きなデータセットには、次のようなデータがあります。

"guide (but, yeah, it’s okay to share it with ‘em)."

16進エディターでファイルを開き、生のバイトデータを文字エンコーディング検出アルゴリズム( http://code.google.com/p/juniversalchardet/ )で実行しました。 UTF-8。

データのソースが元の文字セットを誤って解釈し、受け取った出力として有効なUTF-8を書き込んだようです。

できる限りデータを検証したいのですが。検証時にスタブを取るのに役立つ可能性のあるヒューリスティック/アルゴリズムはありますか?

18
David Parks

ひとたび文字列を取得したら、生の入力がまだある間にそれを実行する必要があります。文字列を取得した後は、’が実際に意図した入力であったかどうかを、非常に脆弱なテストを行わずに自動的に判断する方法はありません。例えば:

public static boolean isUTF8MisInterpreted( String input ) {
          //convenience overload for the most common UTF-8 misinterpretation
          //which is also the case in your question
      return isUTF8MisInterpreted( input, "Windows-1252");  
}

public static boolean isUTF8MisInterpreted( String input, String encoding) {

    CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
    CharsetEncoder encoder = Charset.forName(encoding).newEncoder();
    ByteBuffer tmp;
    try {
        tmp = encoder.encode(CharBuffer.wrap(input));
    }

    catch(CharacterCodingException e) {
        return false;
    }

    try {
        decoder.decode(tmp);
        return true;
    }
    catch(CharacterCodingException e){
        return false;
    }       
}

public static void main(String args[]) {
    String test = "guide (but, yeah, it’s okay to share it with ‘em).";
    String test2 = "guide (but, yeah, it’s okay to share it with ‘em).";
    System.out.println( isUTF8MisInterpreted(test)); //true
    System.out.println( isUTF8MisInterpreted(test2)); //false

}

それでもraw入力にアクセスできる場合は、バイト配列がこれで完全に有効なutf-8バイトシーケンスになるかどうかを確認できます。

public static boolean isValidUTF8( byte[] input ) {

    CharsetDecoder cs = Charset.forName("UTF-8").newDecoder();

    try {
        cs.decode(ByteBuffer.wrap(input));
        return true;
    }
    catch(CharacterCodingException e){
        return false;
    }       
}

CharsetDecoderをストリームで使用することもできます。デフォルトでは、指定されたエンコーディングで無効なバイトが検出されるとすぐに例外がスローされます。

38
Esailija