Java与C#中的不同UTF-16编码

时间:2015-12-08 23:03:27

标签: java c# unicode

在C#与Java中将字符串转换为字节时,我遇到了不同的结果。

C#:

byte[] byteArray =  Encoding.Unicode.GetBytes ("chess ¾");
for (int i = 0; i < byteArray.Length; i++)
    System.Diagnostics.Debug.Write (" " + byteArray[i]);
System.Diagnostics.Debug.WriteLine("");
System.Diagnostics.Debug.WriteLine(Encoding.Unicode.GetString(byteArray));

显示:

99 0 104 0 101 0 115 0 115 0 32 0 190 0
chess ¾

爪哇:

byte[] byteArray = "chess ¾".getBytes("UTF-16LE");
for (int i = 0; i < byteArray.length; i++)
        System.out.print(" " + (byteArray[i]<0?(-byteArray[i]+128):byteArray[i]));
System.out.println("");
System.out.println(new String(byteAppName,"UTF-16LE"));

显示:

99 0 104 0 101 0 115 0 115 0 32 0 194 0
chess ¾

请注意,字节数组中的倒数第二个值是不同的!我的目标是加密这些数据,并能够从C#或Java中读取它。这种差异似乎是一个障碍。

作为旁注,在我学会使用Unicode(C#)/ UTF-16LE(Java)之前,我使用的是UTF-8 ......

C#: byte[] byteArray = Encoding.UTF8.GetBytes ("chess ¾");

显示: 99 104 101 115 115 32 194 190

Java: byteArray = appName.getBytes("UTF-8");

显示: 99 104 101 115 115 32 190 194

其中,奇怪的是导致倒数第二个到最后一个和最后一个字节。

最后,¾的Unicode是十进制190(http://www.fileformat.info/info/unicode/char/BE/index.htm),而不是十进制194(Â)(http://www.fileformat.info/info/unicode/char/00c2/index.htm)。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:4)

你的问题不在于编码,它是你打印结果的方式,你是使用string从字节转换为整数,这会给你不正确的结果,使用其他像{ {1}}而是。使用此poc比较两次转化:

byteArray[i] < 0 ? (-byteArray[i] + 128) : byteArray[i]

答案 1 :(得分:1)

我的猜测。

UTF-16LE表示字符占用2或4个字节。

检查this并向下滚动到3/4。您将看到190和194(11000010 10111110) - 这些是编码符号所需的两个字节,显然称为“VULGAR FRACTION THREE QUARTERS”。

创建byte[]时,数组只能存储1个字节,而不能存储2个字节,因此您将错过一个字节。看起来在C#中你错过了194,在Java中你错过了190。

原因是字节序。请参阅this回答。

  

在Java中,getBytes(“UTF-16”)返回一个big-endian表示。

     

C#的System.Text.Encoding.Unicode.GetBytes返回一个小端表示。

但是,在Java中,getBytes("UTF-16LE")根据this以little-endian返回,这就是你正在使用的。

我现在有疑虑。

我需要更多地思考你在Java中究竟做了什么。还不确定如何解决它。