UTF-16LE和UTF32-LE的Unicode BOM有什么区别?

9
似乎在UTF16-LE和UTF-32LE使用的字节顺序标记之间存在歧义。特别是,考虑一个包含以下8个字节的文件:
FF FE 00 00 00 00 00 00

我如何判断该文件是否包含以下内容:
  1. UTF16-LE BOM(FF FE)后跟3个空字符;或
  2. UTF32-LE BOM(FF FE 00 00)后跟一个空字符?
Unicode BOM在此处描述:http://unicode.org/faq/utf_bom.html#bom4,但没有讨论这种歧义。我有什么遗漏吗?
3个回答

12

正如名称所示,BOM只告诉您字节顺序,而不是编码。您首先必须知道编码是什么,然后才能使用BOM来确定多字节序列的最高有效字节或最低有效字节。

BOM的一个幸运的副作用是,如果您不知道编码,有时也可以使用它来猜测编码,但这不是它的设计目的,也不能代替发送正确的编码信息。


9

这是很明确的。 FF FE 是UTF-16LE的标识,而FF FE 00 00则代表UTF-32LE。没有理由认为FF FE 00 00可能是UTF-16LE,因为UTF是为文本设计的,用户不应该在其文本中使用NUL字符。毕竟,你上一次打开十六进制编辑器并向文本文档中插入几个字节的00是什么时候呢? ^_^


5
空字符可能是文本中编码的更高级协议的一部分。Unicode 实际上并不关心文本中使用哪些代码点,U+0000 和 U+0041 一样有效。 - Joey
3
阅读高阶协议时,这个理论与需要猜测编码的问题设置相冲突。如果你正在阅读协议,则不会猜测编码。 - u0b34a0f6ae
1
换句话说,文件开头有U+0000并非不可能,但十分罕见。如果您读取的数据可能存在这种情况,那么就不应该依赖字节顺序标记来进行格式检测。 - Mark Ransom

1

我曾经遇到和Edward一样的问题。我同意Dustin的观点,通常情况下,在文本文件中不会使用空字符。

然而,我创建了一个包含所有Unicode字符的文件。我首先使用了utf-32le编码,然后是utf-32be编码、utf-16le编码、utf-16be编码以及utf-8编码。

当尝试将文件重新编码为utf-8时,我想将结果与已有的utf-8文件进行比较。由于BOM后我的文件中的第一个字符是空字符,所以我无法成功检测带有utf-16le BOM的文件,它显示为utf-32le BOM,因为字节的出现方式正如Edward所描述的那样。在BOM FFFE之后,第一个字符是0000,但BOM检测却发现了BOM FFFE0000,因此检测到了utf-32le而不是utf-16le,我的第一个0000字符被窃取并作为BOM的一部分。

因此,永远不要在用utf-16小端编码的文件中使用空字符作为第一个字符,因为这会使utf-16le和utf-32le BOM变得模糊不清。

为了解决我的问题,我将交换第一个和第二个字符。 :-)


1
如果你仅依赖BOM来检测编码,那么你需要查看比BOM更多的字节来解决UTF-16/32的歧义。首先检查UTF-16LE,如果检测到,则检查后续的N*2个字节是否是有效的UTF-16LE,其中N是一个合理的数字。如果不是有效的UTF-16LE,则重新开始并假定为UTF-32LE。U+0000应该是唯一有歧义的代码点,在文件开头不应该有太多的空字符。在某个时候,必须有一个截止点,如果到那时仍然无法解决歧义,则提示用户或以错误失败处理。 - Remy Lebeau
这意味着,如果检测到一个utf-32le BOM,应该首先检查它是否真的是一个utf-16le BOM,并且后面跟着一个U+0000的代码点。如果有很多单词,这可能会有所帮助,可能还可以检测代理项。但如果只有几个单词,这可能会很困难。但我同意,当检查有效的utf-32代码点时,如果它确实是一个utf-16编码的文件,可能会发现超过0x10FFFF最大值的代码点。无论如何,我们应该建议在utf-16le编码的文件中始终放置另一个代码点而不是U+0000作为第一个代码点。 - brighty

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