我已经发布了一个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)中。
我的问题:
感谢您的耐心等待。
答案 0 :(得分:5)
为什么utf-8不理解这种编码?
是吗? UTF-8是一种编码。它不懂编码。您的编辑器是理解编码的,它对UTF-8,UTF-16le和UTF-16be的理解不一定相关。
为什么编辑会显示中文字符?
(A)中的问题是您的编辑器使用UTF-16be来解码使用UTF-16le编码的文档。
我是错的还是这个问题(插入“@”)由于xml文件的规范错误?
该文件是正确的。该文件使用UTF-16le。它指定它使用encoding="utf-16"
和BOM。
(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)
你似乎不知道有各种各样的事情:
TL; DR:编码是双射部分函数,它将字节序列映射到字符序列并再次返回。 Unicode是一个很大的字符列表,每个字符都有一个数字(代码点)。各种编码用于将这些代码点映射到字节:
0xFEFF
或0xFFFE
对此进行排序,其中一个标记位于每个UTF-16文档之前。某些字符(“控制字符”)没有可打印的解释。在hexdump中,不可打印的字节用.
表示。 Emacs和Vim遵循使用^
为控制代码加前缀的传统路线,这意味着它与下一个字符一起代表控制代码。 ^@
表示NUL字符,而^H
表示退格,^D
表示传输结束。通过从可视化表示中的ASCII字符中减去0x40
,可以获得控制字符的ASCII值。 \377
是0xFF
的八进制表示。
XML的默认编码是UTF-8,因为它向后兼容ASCII。使用任何其他编码是不必要的痛苦,正如这个问题所证明的那样。无论如何,UTF-16 可以使用,如果正确声明(你的输入尝试),但然后搞砸了。
您的文件包含以下部分:
0xFFFE
,这意味着第一个字节是输入中的低字节。然后是ASCII字符后跟一个NUL字节。0d00 0d0a
。 0d00
是CR
,回车。第二部分是0a00
,换行。它们一起构成了Windows系列的结尾。 0d0a
将是 ASCII CRLF。但这是错误的,因为UTF-16是一个双字节编码。发生了什么:
有人打印出以UTF-16le编码的XML前导码。最后的\n
自动翻译为\r\n
。因此0d00 0a00
成了0d00 0d0a 00
。
当您不解码输入时,可能会在Perl中发生这种情况,但会对输出进行编码。在Windows上,Perl会自动换行,可以通过binmode $fh
关闭。
如果您的脚本可以修复此错误,那么它会反过来犯同样的错误(将\r\n
翻译为\n
,然后然后解码它。)
通过直接解码所有输入并在打印之前再次对其进行编码,可以避免此类错误。在内部,始终对代码点进行操作,而不是字节。在Perl编码中可以添加binmode
的文件句柄,它可以透明地执行解码和编码。