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(...)调用后仍有多少字节未使用来检查我的理论/解释是否正确。


如果我的理论是正确的,那么答案是您不能通过为解码器提供恰好包含一个字节的字节缓冲区来解码 UTF-8。但是您可以通过从包含一个字节的 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 回答