字符串UTF8编码问题

4
下面这个简单的测试失败了:
assertEquals(myStringComingFromTheDB, "£");

给予:

Expected :£
Actual   :£

我不明白为什么会出现这种情况,尤其是考虑到实际字符串的编码(第二个参数指定的那个)是错误的。Java文件以UTF8保存。

以下是代码:

System.out.println(bytesToHex(myStringComingFromTheDB.getBytes()));
System.out.println(bytesToHex("£".getBytes()));

输出:

C2A3
C382C2A3

有谁可以解释一下为什么吗?

谢谢。

更新:我正在Windows 7下工作。

更新2:这与JUnit无关,以下是一个简单的示例:

byte[] bytes = "£".getBytes();
for(byte b : bytes)
{
    System.out.println(Integer.toHexString(b));
}

输出:

ffffffc3
ffffff82
ffffffc2
ffffffa3

更新3: 我正在使用IntelliJ Idea进行工作,已经检查了选项并且编码是UTF8。此外,在底部栏中写着,当我选择并右键单击英镑符号时,它会显示“编码(自动检测):UTF-8”。

更新4: 使用十六进制编辑器打开Java文件,英镑符号以“C2A3”的形式正确保存。

1个回答

3
请注意,assertEquals接受以下顺序的参数:
assertEquals(expected, actual)

在您的情况下,来自数据库的字符串是可以的,但来自Java类的字符串不行(正如您已经注意到的那样)。

我猜你从某个地方复制了一个 £ 符号 - 可能带有一些奇怪的字符环绕它,您的编辑器(IDE)不会将其打印出来(几乎肯定)。我曾经遇到过类似的问题,特别是当我在MS Windows上工作时:例如从网站 ctrl+c & ctrl+v 到IDE。

(我用UTF8编码在我的系统上打印了 £ 的字节,结果是 C2A3):

for (byte b: "£".getBytes()) {
  System.out.println(Integer.toHexString(b));
}

另一个解决方法可能是您的文件实际上并不是UTF-8编码。您在Windows或其他操作系统上工作吗?
根据问题编辑,还有一些其他可能的解决方案:
1)可能是IDE使用了其他编码方式。对于eclipse,请参见此线程:http://www.eclipse.org/forums/index.php?t=msg&goto=543800& 2)如果IDE设置和最终文件编码都没有问题,则是编译器问题。请参见:Java编译器平台文件编码问题

感谢您的回答,@PiotrekDe。我也认为ctrl+c和ctrl+v是一样的,但我用键盘手动输入时仍然遇到了问题。我正在使用Windows 7。这个问题真的很奇怪,让我感到很害怕! - satoshi
我正在使用IntelliJ Idea进行工作,编码方式为UTF8。我已经检查了选项,它也是UTF8。此外,在底部栏中写着,并且当我选择英镑符号时,它会显示“编码(自动检测):UTF-8”。 - satoshi
2
所以如果不是键盘,也不是IDE和文件,最后的机会就是编译器 :): https://dev59.com/uFTTa4cB1Zd3GeqPpRx8 - omnomnom
1
你是对的,现在它完美地工作了!我检查了编译器,发现它使用的是 aspectjtools-1.6.10.jar 而不是 javac。我还添加了参数 -encoding UTF-8。如果你修改了你的答案或者添加了一个新的答案,我会点赞并接受它 :) 谢谢! - satoshi
2
如果UTF-8编码是文件格式规范的一部分,最好使用myStringComingFromTheDB.getBytes("UTF-8")。无参数的String.getBytes()使用平台编码,因此在不同的机器上结果可能会有所不同,并且您可能会遇到棘手的错误(例如,在开发机器上一切正常,但在生产中停止工作,因为机器意外地使用了不同的语言环境)。相反的操作也是如此,即从字节数组创建一个字符串。 - Michał Kosmulski
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接