3

これが私の問題です。バイト配列に変換した InputStream がありますが、実行時の InputStream の文字セットがわかりません。私の最初の考えでは、すべてを UTF-8 で行うことでしたが、ISO-8859-1 としてエンコードされ、外国語の文字を含むストリームで奇妙な問題が発生しました。(狂ったスウェーデン人)

問題のコードは次のとおりです。

IOUtils.toString(inputstream, "utf-8")
// Fails on iso8859-1 foreign characters

これをシミュレートするために、次のものがあります。

new String("\u00F6")
// Returns ö as expected, since the default encoding is UTF-8

new String("\u00F6".getBytes("utf-8"), "utf-8")
// Also returns ö as expected.

new String("\u00F6".getBytes("iso-8859-1"), "utf-8")
// Returns \uffff, the unknown character

私は何が欠けていますか?

4

2 に答える 2

4

すべてのバイト シーケンスが有効な UTF-8 文字であるとは限りません。一部のバイト シーケンスは有効ではなく、\u00F6同等の Latin-1 文字に変換することで、有効な UTF-8 ではないものを作成しました。

于 2013-02-06T03:49:12.843 に答える
1

エンコーディングを示すデータのソースが必要ですが、それが不可能な場合は、それを拒否するか、UTF-8でない場合はエンコーディングを推測する必要があります。

西洋言語の場合、UTF-8でない場合にISO-8859-1を推測することは、おそらくほとんどの場合機能します。

ByteBuffer bytes = ByteBuffer.wrap(IOUtils.toByteArray(inputstream));
CharBuffer chars; 

try {
    try {
        chars = Charset.forName("UTF-8").newDecoder().decode(bytes);
    } catch (MalformedInputException e) {
        throw new RuntimeException(e);
    } catch (UnmappableCharacterException e) {
        throw new RuntimeException(e);
    } catch (CharacterCodingException e) {
        throw new RuntimeException(e);
    }
} catch (RuntimeException e) {
    chars = Charset.forName("ISO-8859-1").newDecoder().decode(bytes);
} 
System.out.println(chars.toString());

この定型文はすべて、エンコーディング例外を取得し、同じデータを複数回読み取ることができるようにするためのものです。

UTF-8でない場合は、より高度なヒューリスティックを使用してエンコーディングを決定するMozillaChardetを使用することもできます。しかし、それは完璧ではありません。たとえば、Windows-1252でフィンランド語のテキストをヘブライ語のWindows-1255として検出したことを思い出します。

また、任意のバイナリデータはISO-8859-1で有効であるため、UTF-8を最初に検出するのはこのためです(例外なくUTF-8を通過する場合はUTF-8と非常によく似ています)。 ISO-8859-1以降は何も検出できません。

于 2013-02-06T10:35:33.767 に答える