4

文字セットデコーダーを使用してUTF8をバイトごとにデコードしようとしています。これは可能ですか?

次のコード

public static void main(String[] args) {

    Charset cs = Charset.forName("utf8");
    CharsetDecoder decoder = cs.newDecoder();
    CoderResult res;

    byte[] source = new byte[] {(byte)0xc3, (byte)0xa6}; // LATIN SMALL LETTER AE in UTF8

    byte[] b = new byte[1];
    ByteBuffer bb = ByteBuffer.wrap(b);

    char[] c = new char[1];
    CharBuffer cb = CharBuffer.wrap(c);

    decoder.reset();

    b[0] = source[0];
    bb.rewind();

    cb.rewind();
    res = decoder.decode(bb, cb, false);

    System.out.println(res);
    System.out.println(cb.remaining());

    b[0] = source[1];
    bb.rewind();

    cb.rewind();
    res = decoder.decode(bb, cb, false);

    System.out.println(res);
    System.out.println(cb.remaining());



}

次の出力が得られます。

UNDERFLOW
1
MALFORMED[1]
1

なんで?

4

2 に答える 2

4

私の理論では、これを行う方法の問題は、「アンダーフロー」状態では、デコーダーが未消費のバイトを入力バッファーに残すことです。少なくとも、それは私の読書です。

javadocの次の文に注意してください。

「いずれにせよ、このメソッドを同じデコード操作で再度呼び出す場合は、次の呼び出しで使用できるように、入力バッファーに残っているバイトを保持するように注意する必要があります。」

しかし、あなたは(おそらく)未読のバイトを壊しているのです。

bb最初のdecode(...)呼び出し後に消費されていないバイト数を調べることで、私の理論/解釈が正しいかどうかを確認できるはずです。


私の理論が正しければ、答えは、正確に1バイトを含むバイトバッファをデコーダに提供することによってUTF-8をデコードすることはできないということです。ただし、1バイトを含むByteBufferから開始し、デコーダーが文字の出力に成功するまでバイトを追加することで、バイトごとのデコードを実装できます。まだ消費されていない入力バイトを壊さないように注意してください。

このようなデコードは効率的ではないことに注意してください。API設計は、一度に多数のバイトをデコードするように最適化されています。

于 2013-02-09T23:59:57.863 に答える
3

すでに述べたように、utfの文字数は1〜6バイトです。デコードする前に、すべてのバイトをバイトバッファに追加する必要があります。これを試してください。

public static void main(String[] args) {

    Charset cs = Charset.forName("utf8");
    CharsetDecoder decoder = cs.newDecoder();
    CoderResult res;

    byte[] source = new byte[] {(byte)0xc3, (byte)0xa6}; // LATIN SMALL LETTER AE in UTF8

    byte[] b = new byte[2]; //two bytes for this char
    ByteBuffer bb = ByteBuffer.wrap(b);

    char[] c = new char[1];
    CharBuffer cb = CharBuffer.wrap(c);

    decoder.reset();

    b[0] = source[0];
    b[1] = source[1];
    bb.rewind();

    cb.rewind();
    res = decoder.decode(bb, cb, false); //translates 2 bytes to 1 char

    System.out.println(cb.remaining()); //prints 0
    System.out.println(cb.get(0)); //prints latin ae

}
于 2013-02-09T23:29:43.730 に答える