java,utf8,国际字符和字节解释

时间:2016-09-14 16:15:23

标签: java unicode encoding utf-8

我有一个String,可以输入我的程序。

4个字母A,O," E带有变音符号",L

" E的十六进制代码,带有变音符号"是0xc38b。见UTF-8 encoding table and Unicode characters并寻找"拉丁文大写字母E与DIAERESIS"

然后它变得奇怪

我的java代码不打印" E带有变音符号"但" A与〜"接着是0x8b

当我将字符串转换为字节数组并将其打印为十六进制时,我的4个字符串变为7个字符:

byte[0]=41 "A"
byte[1]=4f "O"
byte[2]=c3 c383 is "A with a ~" (per above link)
byte[3]=83
byte[4]=c2 c28b is some kind of control character (per above link)
byte[5]=8b
byte[6]=4c "L"

我已经通过Charset.defaultCharset()验证了我的编码是UTF-8

它几乎看起来不正确地解释了字节,但这怎么可能?

任何人都可以解释为什么这个字符串的字节解释被搞砸了以及我如何纠正它?

2 个答案:

答案 0 :(得分:5)

沿线的某处,您的输入使用UTF-8编码,然后使用ISO 8859-1(或类似的单字节编码)进行解码。此时字符串已损坏。

使用UTF-8编码"Ë"会产生字节[ 0xC3 0x8B ]。使用ISO 8859-1对此进行解码会生成损坏的字符串"Ë""\u00C3\u008B")。使用UTF-8重新编码该字符串会生成原始问题[ 0xC3 0x83 0xC2 0x8B ]

中的字节序列

确定ISO 8859-1被错误地用于解码UTF-8数据的位置,并指定UTF-8。

这是解码Web请求或响应时的常见问题。除非明确覆盖,否则标准将ISO 8859-1指定为字符编码,因此框架将作为默认值回退到此。

答案 1 :(得分:0)

是的,一切都是正确的。 U + 7F以上的非Unicode字符,非7位ASCII,用多个字节编码,如(荷兰语)U + C38B。该序列的每个字节都有高位设置。在其他字符集中,如某些Windows单字节字符集,将是两个或更多奇怪的字符。

String s = "Zee\uC38Bn van tijd in Belgi\uC38B\r\n";
Path path = "C:/temp/test.txt";
Files.write(path, ("\uFEFF" + s).getBytes(StandardCharsets.UTF_8));

上面在开头写了一个带有BOM char(零宽度空间)的文本文件(U + FEFF)。这是一种丑陋的冗余,可帮助Windows Notepad将文件识别为UTF-8。

澄清

Unicode字符U + C38B,在java中的java char' \ uC38B'实际上是。确实在UTF-8中转换为4个字节。

Ë实际上是U + CB或'\u00CB'。它在UTF-8中的字节表示如下:

String s = new String(new byte[]{ (byte)0xC3, (byte)0x8B}, 0, 2, StandardCharsets.UTF_8);

UTF-8完全不同于简单地分割该字符的(顺序)Unicode数字有几个目的:字节序列可识别为多字节序列的一部分:开始和继续字节,以及普通ASCII,如{{ 1}}永远不能成为这样一个字节序列的一部分。所以普通的ASCII是安全的。