【问题标题】:String differs after encoding and decoding编码和解码后字符串不同
【发布时间】:2018-10-23 12:04:35
【问题描述】:

我偶然发现了编码/解码字符串的奇怪行为。看一个例子:

@Test
public void testEncoding() {
    String str = "\uDD71"; // {56689}
    byte[] utf16 = str.getBytes(StandardCharsets.UTF_16); // {-2, -1, -1, -3}
    String utf16String = new String(utf16, StandardCharsets.UTF_16); // {65533}
    assertEquals(str, utf16String);
}

我认为这个测试会通过,但事实并非如此。有人可以解释为什么编码和解码的字符串不等于原始字符串吗?

【问题讨论】:

  • 你必须至少显示实际输出
  • 您想查看哪个输出?字节数组? utf16字符串?以什么形式?我认为你可以很容易地自己运行这个测试。一般来说,输出是那些字符串是不同的
  • \uDD71 是低代理。单独它是无用的,不表示任何代码点。因此它被替换为\uFFFD
  • 如果您更喜欢异常而不是替换,请避免使用 String 构造函数。

标签: java string unicode character-encoding unicode-literals


【解决方案1】:

U+DD71 不是有效的代码点,因为 U+D800..U+DFFF 由 Unicode 保留,以免与 UTF-16 混淆。因此,这些代码点永远不应显示为有效的字符数据。来自 Unicode 标准:

孤立的代理代码点没有解释;因此,没有提供字符代码图表或名称列表 这个范围。

不过,这行得通:

@Test
public void testEncoding() {
    String str = "\u0040";
    byte[] utf16 = str.getBytes(StandardCharsets.UTF_16);
    String utf16String = new String(utf16, StandardCharsets.UTF_16);
    assertEquals(str, utf16String);
}

所以,不是您的代码有问题,而是您尝试使用无效的代码点。

【讨论】:

  • 我已经接受了你的回答,但非常感谢@Johannes Kuhn,他是第一个帮助我理解问题的人。
  • 是的,我回答完后看到了他的评论。他比我更了解这个主题,但这是谷歌搜索告诉我的。
猜你喜欢
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多