0

我已经发布了一个 xml-utf16 问题 ,如果我打开 xml 文件,Emacs 会显示汉字, 但现在我想了解为什么会出现这种问题。也许,如果我有更深入的了解,我可以更好地应对这类问题。

具体来说,我得到了一个用 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) 中。

在此处输入图像描述

我的问题:

  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 包,不是吗?
  4. 为什么导出数据并生成正在研究的 xml 文件的导出器在被编辑器打开时不考虑 LF/CR 以获得可读的 xml 文件?这是为了避免大文件吗?
  5. 关于 utf16 存在争议(https://softwareengineering.stackexchange.com/questions/102205/should-utf-16-be-considered-harmful)。使用 utf16 显然存在问题,这个问题是大约 4 年前提出的。为什么程序员仍然使用 utf16?我错过了什么吗?(我想建议我的数据交付者使用 utf8)。

谢谢你的耐心。

4

2 回答 2

6

有很多事情你似乎不知道:

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

基本

这只是Joel Spolsky 的“每个软件开发人员绝对、肯定必须了解 Unicode 和字符集(没有借口!)的绝对最低要求”的链接。

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

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

二进制数据的可视化表示

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

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 上,Perl 会自动进行换行转换,这可以通过binmode $fh.

  2. 文档的其余部分打印在一行中,因此没有发生进一步的翻译。因为一个字节的添加改变了一切,解释发生了巨大的变化。

如果您的脚本可以修复此错误,那么它会在反向中犯同样的错误(翻译\r\n\n然后对其进行解码)。

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

于 2013-09-16T16:03:44.200 回答
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 来说,这似乎是一个相当激进的解决方案。

于 2013-09-16T15:22:05.500 回答