当打开带有utf-16的xml文件时,编辑器显示中文字符

时间:2013-09-16 14:42:06

标签: xml perl emacs utf-8 utf-16

我已经发布了一个xml-utf16问题 Emacs displays chinese character if I open xml file 但现在我想解释为什么会出现这种问题。也许,如果我有更深入的了解,我可以更好地应对这类问题。

具体来说,我得到了一个用utf16编码的xml文件。我使用emacs(记事本,firefox)从windows xp PC打开文件,显示图(A)(firefox说:格式不正确)。显然,该文件是使用utf16编码导出的。 (B)显示十六进制版本。 (C)使用emacs(revert-buffer-with-coding-system)转换为utf-8后显示xml文件。我还将带有Perl的xml-utf16文件转换为utf8。结果显示在(D)中。

enter image description here

我的问题:

  1. 显然,xml文件是使用utf-16le编码导出的。根据我的理解,utf-16是比utf-8更简单,更旧的编码。为什么utf-8不理解这种编码?为什么编辑会显示中文字符?
  2. 如果我想阅读xml文件的内容,建议将其转换为emacs。由于“@”,我得到的是不可读的(C)。我认为编码问题是一个常见的任务,像emacs这样的编辑可以应对。我错了还是这个问题(插入“@”)由于xml文件的规范错误?为什么字符之间的十六进制版本有一点?
  3. 我从互联网上下载了一个将utf16转换为utf8的Perl代码。如果我将原始的xml文件转换为utf-8,我得到了数字(D)。好消息是firefox显示新xml文件的树结构。使用emacs(D)不是这种情况。整个内容写在一行(第一行除外)。实际上,原始文件不包含CR或LF。如果我想看到考虑树结构的utf16 / utf8 xml文件,那么编写Perl或Python代码似乎是我的工作,它通过插入CR / LF或使用适当的Perl来考虑树结构/ Python-package,不是吗?
  4. 为什么导出数据并生成正在研究的xml文件的导出器在编辑器打开时不考虑LF / CR获取可读的xml文件?这是为了避免大文件大小吗?
  5. 关于utf16(https://softwareengineering.stackexchange.com/questions/102205/should-utf-16-be-considered-harmful)的辩论。使用utf16显然存在问题,这个问题大约在4年前被问到。为什么程序员仍然使用utf16?我错过了什么吗? (我想建议我的数据传递者使用utf8)。
  6. 感谢您的耐心等待。

2 个答案:

答案 0 :(得分:5)

  

为什么utf-8不理解这种编码?

是吗? UTF-8是一种编码。它不懂编码。您的编辑器是理解编码的,它对UTF-8,UTF-16le和UTF-16be的理解不一定相关。

  

为什么编辑会显示中文字符?

(A)中的问题是您的编辑器使用UTF-16be来解码使用UTF-16le编码的文档。

  

我是错的还是这个问题(插入“@”)由于xml文件的规范错误?

该文件是正确的。该文件使用UTF-16le。它指定它使用encoding="utf-16"和BOM。

使用UTF-16le

(C)中的问题是您的编辑器使用单字节编码来解码使用UTF-16le编码的文档。 ^@代表NUL。

  

为什么字符之间的十六进制版本有一个点?

没有。最右边的列显示使用US-ASCII解码的文件的内容,这显然不是。

  

如果我想看一下考虑树结构的utf16 / utf8 xml文件

...那么你需要一个XML查看器/编辑器,它以该形式显示XML,而不是文本编辑器。

  

为什么导出数据并生成正在研究的xml文件的导出器在编辑器打开时不考虑LF / CR获取可读的xml文件?

简单。

  

有关于utf16的争论

完全相同的问题发生在UTF-8级别,因为人们没有正确处理字形。如果你正确处理字形,UTF-16的“问题”就会消失。

因此,拒绝UTF-16是因为它是一种可变宽度编码,很少有人认为它对我来说没有意义,因为它与UTF-8相同。

  

为什么程序员仍然使用utf16?我错过了什么吗?

这是Windows内部使用的。

  

我想建议我的数据传递者使用utf8

对于您在emacs中错误地使用UTF-16be而不是UTF-16le,似乎是一个相当激烈的解决方案。

答案 1 :(得分:5)

你似乎不知道有各种各样的事情:

  • 什么是字符,什么是编码?
  • 什么是Unicode?
  • 什么是各种Unicode编码,它们如何区别,它们的优点和缺点是什么,它们的历史是什么?
  • XML规范对编码有何看法?
  • 各种操作系统如何与编码互动?
  • 如何直观地表示二进制数据?
  • XML中的空格是做什么的?
  • ...

基本

这只是指向“The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)” by Joel Spolsky的链接。

TL; DR:编码是双射部分函数,​​它将字节序列映射到字符序列并再次返回。 Unicode是一个很大的字符列表,每个字符都有一个数字(代码点)。各种编码用于将这些代码点映射到字节:

  • ASCII,只能代表128个不同的字符。
  • UTF-16,每个代码点使用至少两个字节。这可以包括空字节。这种编码是模糊的:读取的字节在哪个方向?字节顺序标记0xFEFF0xFFFE对此进行排序,其中一个标记位于每个UTF-16文档之前。
  • UTF-8为每个字符使用至少一个字节,并具有ASCII是UTF-8的子集的属性。它不能包含空字节(好吧,除了实际的NUL)。这种编码的缺点是非常高的代码点具有大的表示。与UTF-8相比,UTF-16中的CJK文本可以用更少的字节表示。对于西方文本,它是相反的。

二进制数据的可视化表示

某些字符(“控制字符”)没有可打印的解释。在hexdump中,不可打印的字节用.表示。 Emacs和Vim遵循使用^为控制代码加前缀的传统路线,这意味着它与下一个字符一起代表控制代码。 ^@表示NUL字符,而^H表示退格,^D表示传输结束。通过从可视化表示中的ASCII字符中减去0x40,可以获得控制字符的ASCII值。 \3770xFF的八进制表示。

XML和编码

XML的默认编码是UTF-8,因为它向后兼容ASCII。使用任何其他编码是不必要的痛苦,正如这个问题所证明的那样。无论如何,UTF-16 可以使用,如果正确声明(你的输入尝试),但然后搞砸了。

您输入的问题。

您的文件包含以下部分:

  • BOM 0xFFFE,这意味着第一个字节是输入中的低字节。然后是ASCII字符后跟一个NUL字节。
  • 输入的第一行(最多为hexdump中的字节0x52)包含正确编码的XML声明。
  • 然后,发生了一些不好的事情:我们得到序列0d00 0d0a0d00CR,回车。第二部分是0a00,换行。它们一起构成了Windows系列的结尾。 0d0a将是 ASCII CRLF。但这是错误的,因为UTF-16是一个双字节编码。
  • 之后,UTF-16继续,但现在NUL在每个角色之前:另一个UTF-16版本!但你的编辑不知道这一点,并给你美丽的汉字。

发生了什么:

  1. 有人打印出以UTF-16le编码的XML前导码。最后的\n自动翻译为\r\n。因此0d00 0a00成了0d00 0d0a 00

    当您不解码输入时,可能会在Perl中发生这种情况,但会对输出进行编码。在Windows上,Pe​​rl会自动换行,可以通过binmode $fh关闭。

  2. 文档的其余部分打印在一行中,因此没有进一步的翻译。因为单个字节的添加改变了所有内容,所以解释发生了巨大的变化。
  3. 如果您的脚本可以修复此错误,那么它会反过来犯同样的错误(将\r\n翻译为\n,然后然后解码它。)

    通过直接解码所有输入并在打印之前再次对其进行编码,可以避免此类错误。在内部,始终对代码点进行操作,而不是字节。在Perl编码中可以添加binmode的文件句柄,它可以透明地执行解码和编码。