我试图根据字符集对字符,它们在字节序列中的表示进行排序,以及如何在Java中将一个字符集转换为另一个字符集。我有些困难。
例如,
ByteBuffer bybf = ByteBuffer.wrap("Olé".getBytes());
我的理解是:
getBytes()
结果是相同的UTF-16字节序列wrap()
维持此序列bybf
因此是字符串Olé
因此在此代码中:
Charset utf16 = Charset.forName("UTF-16");
CharBuffer chbf = utf16.decode(bybf);
System.out.println(chbf);
decode()
应该
bybf
解释为UTF-16字符串表示Olé
。 实际上不应该更改任何字节,因为所有内容都是UTF-16存储的,而UTF-16 Charset
应该是一种"中立运算符"。但结果打印为:
??
怎么可能?
其他问题:为了正确转换,似乎Charset.decode(ByteBuffer bb)
要求bb
是字符串的UTF-16大端字节序列图像。 这是正确的吗?
修改:从提供的答案中,我做了一些测试来打印ByteBuffer
内容和通过解码获得的chars
。字节[编码与= "Olé".getBytes(charsetName)
]打印在第一行组上,其他行是通过用各种Charset#decode(ByteBuffer)
解码字节[与Charset
]获得的字符串。
我还确认在Windows 7计算机上将String存储到byte[]
的默认编码是windows-1252
(除非字符串包含需要UTF-8的字符)。
Default VM encoding: windows-1252
Sample string: "Olé"
getBytes() no CS provided : 79 108 233 <-- default (windows-1252), 1 byte per char
Decoded as windows-1252: Olé <-- using the same CS than getBytes()
Decoded as UTF-16: ?? <-- using another CS (doesn't work indeed)
getBytes with windows-1252: 79 108 233 <-- same than getBytes()
Decoded as windows-1252: Olé
getBytes with UTF-8: 79 108 195 169 <-- 'é' in UTF-8 use 2 bytes
Decoded as UTF-8: Olé
getBytes with UTF-16: 254 255 0 79 0 108 0 233 <-- each char uses 2 bytes with UTF-16
Decoded as UTF-16: Olé (254-255 is an encoding tag)
答案 0 :(得分:7)
你大多是正确的。
java中的本机字符表示形式为UTF-16。但是,在将字符转换为字节时,您可以指定正在使用的字符集,或者系统使用它的默认值,每当我检查时,它通常为UTF-8。如果您正在混合和匹配,这将产生有趣的结果。
例如我的系统如下
System.out.println(Charset.defaultCharset().name());
ByteBuffer bybf = ByteBuffer.wrap("Olé".getBytes());
Charset utf16 = Charset.forName("UTF-16");
CharBuffer chbf = utf16.decode(bybf);
System.out.println(chbf);
bybf = ByteBuffer.wrap("Olé".getBytes(utf16));
chbf = utf16.decode(bybf);
System.out.println(chbf);
生成
UTF-8
佬쎩
奥莱
所以这部分只有在UTF-16是默认字符集时才是正确的
getBytes() result is this same UTF-16 byte sequence.
因此要么始终指定您正在使用的最安全的字符集,因为您将始终知道发生了什么,或者始终使用默认值。
答案 1 :(得分:7)
字符串始终以Java格式存储为UTF-16字节序列(每个字符2个字节,大端字节)
是
getBytes()结果是相同的UTF-16字节序列
没有。它将UTF-16字符编码到平台默认字符集中,无论是什么。弃用。
wrap()维护这个序列
wrap()
维护一切。
bybf因此是字符串Olé
的UTF-16大端表示
没有。它包装了平台原始字符串的默认编码。
decode()应该
- 将bybf解释为UTF-16字符串表示
不,见上文。
- 将其“转换”为原始字符串Olé。
除非平台的默认编码是“UTF-16”。
答案 2 :(得分:0)
我在使用双字节字符集编码的数据时遇到了几乎相同的问题。 上面的答案3已经包含了你应该关注的重要缺陷。
以下代码正常工作
public static String convertUTF16ToString(byte[] doc)
{
final Charset doublebyte = StandardCharsets.UTF_16;
// Don't need this because it is my local (system default).
//final Charset ansiCharset = StandardCharsets.ISO_8859_1;
final CharBuffer encoded = doublebyte.decode(ByteBuffer.wrap(doc));
StringBuffer sb = new StringBuffer(encoded);
return sb.toString();
}
用您喜欢的编码替换系统默认值。
public static String convertUTF16ToUTF8(byte[] doc)
{
final Charset doublebyte = StandardCharsets.UTF_16;
final Charset utfCharset = StandardCharsets.UTF_8;
final Charset ansiCharset = StandardCharsets.ISO_8859_1;
final CharBuffer encoded1 = doublebyte.decode(ByteBuffer.wrap(doc));
StringBuffer sb = new StringBuffer(encoded1);
final byte[] result = ansiCharset.encode(encoded1).array();
// alternative to utf-8
//final byte[] result = utfCharset.encode(encoded1).array();
return new String(result);
}