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

本文关键字:编码 UTF-16 中的 Java | 更新日期: 2023-09-27 18:26:13

在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 ¾

Java:

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)。

如有任何帮助,我们将不胜感激。

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

问题不在于编码,而在于打印结果的方式,您使用byteArray[i] < 0 ? (-byteArray[i] + 128) : byteArray[i]从字节转换为整数,这会给您带来不正确的结果,请使用byteArray[i] & 0xFF等其他方法。使用以下poc:比较两种转换

    String encoding = "UTF-16LE";
    byte[] byteArray = "chess ¾".getBytes(encoding);
    for (int i = 0; i < byteArray.length; i++) {
        // your conversion
        System.out.print(" " + (byteArray[i] < 0 ? (-byteArray[i] + 128) : byteArray[i]));
       // a more appropriate one
        System.out.print("(" + (byteArray[i] & 0xFF) + ") ");
    }
    System.out.println("");
    System.out.println(new String(byteArray, encoding));

我的猜测。

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

看看这个,向下滚动到3/4。你会看到190和194(1100001010111110)-这是你需要编码符号的两个字节,它显然被称为";VULGAR分数四分之三";。

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

原因是endianness。看看这个答案。

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

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

然而,在Java中,getBytes("UTF-16LE")根据这个以小端序返回,这就是您正在使用的。

我现在有点怀疑。

我需要更多地思考您在Java中到底在做什么。还不确定如何解决。