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

Java与C中不同的UTF-16编码#,java,c#,unicode,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.Diagnos

在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));
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"));
Java:

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));
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"));
请注意,字节数组中倒数第二个值是不同的!我的目标是对这些数据进行加密,并能够从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(),而不是十进制194()

任何帮助都将不胜感激。

我猜

UTF-16LE表示字符需要2或4个字节

签出并向下滚动至3/4。您将看到一个190和一个194(11000010 10111110)-这是编码符号所需的两个字节,它显然被称为“普通分数四分之三”

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

原因是持久性。见答案

在Java中,getBytes(“UTF-16”)返回一个大端表示

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

然而,在Java中,
getBytes(“UTF-16LE”)
根据返回的是小尾端,这就是您正在使用的

我现在有点怀疑


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

您的问题不在于编码,而在于打印结果的方式,您正在使用
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));
String encoding=“UTF-16LE”;
字节[]byteArray=“chess¾”.getBytes(编码);
for(int i=0;i
好奇-如果手动将字节数组从一个放入另一个(即:尝试解码字节),会得到什么样的输出?哦,欢迎来到StackOverflow!这是一个很好的第一个问题:)好的问题:在Java中:
byteArray=newbyte[]{99,0,104,0,101,0,115,0,115,0,32,0,-62,0}显示:
99010401150115032101900
chess
和C语言:
byte[]byteArray=新字节[]{99,0,104,0,101,0,115,0,115,0,32,0,194,0}显示:
99 0 104 0 101 0 115 0 115 0 32 0 194 0
chess
@Chris-谢谢您的回复。非常感谢您的任何见解。谢谢您的回复,@Pushkin。像您这样的担忧让我不再使用UTF-8到UTF-16LE(以及UTF-16BE)。UTF-8到
byte[]
的转换没有丢失任何字节,但它们的顺序在C#和Java之间是不同的(我编辑了我的原始帖子来说明这一点)。请参阅本文()了解我开始使用UTF-16LE的原因。UTF-16总是以16位的块为单位,每个字符有一个或两个块“编码是可变长度的,因为代码点是用一个或两个16位代码单元编码的。”这也意味着使用UTF-8也可以很好地工作。我只想补充一点,问题不是溢出。只是所用的公式是错误的,简单明了<代码>字节数组[i]<0?例如,byteArray[i]+256:byteArray[i]
也可以正常工作。@sstan您是对的,让我们称之为由
-
操作引起的“下溢”,如
字节b=-1;System.out.println(“>>”+(-b))
会在一秒钟内生成
>1
,而不是
>-2
@sstan尽管如此,您是对的,问题不是下溢/溢出,使用的公式完全错误谢谢大家-非常感谢您的帮助。这是我最喜欢的犯错方式。