UTF-8和UTF-8与BOM有什么不同?哪个更好?


当前回答

将BOM放在UTF-8编码的文件中至少有三个问题。

不包含文本的文件不再为空,因为它们始终包含BOM。 在UTF-8的ASCII子集中保存文本的文件本身不再是ASCII,因为BOM不是ASCII,这使得一些现有工具无法使用,用户可能不可能替换这些遗留工具。 不可能将几个文件连接在一起,因为现在每个文件开头都有一个BOM。

而且,正如其他人所提到的,使用BOM来检测某些东西是否是UTF-8是既不够也没有必要的:

这是不够的,因为任意字节序列可能恰好以构成BOM的确切序列开始。 这是不必要的,因为你可以像读取UTF-8一样读取字节;如果成功,根据定义,它是有效的UTF-8。

其他回答

UTF-8 BOM是文本流开头的字节序列(0xEF, 0xBB, 0xBF),它允许读者更可靠地猜测文件是否以UTF-8编码。

通常,BOM用于表示编码的字节顺序,但由于字节顺序与UTF-8无关,因此BOM是不必要的。

根据Unicode标准,不建议使用UTF-8文件的BOM:

2.6编码方案 ... 对于UTF-8,既不要求也不建议使用BOM,但在将UTF-8数据从使用BOM的其他编码形式转换或将BOM用作UTF-8签名的上下文中可能会遇到这种情况。有关更多信息,请参阅第16.8节特殊项中的“字节顺序标记”小节。

其他优秀的回答已经回答过了

UTF-8和BOM-ed的UTF-8之间没有官方的区别 一个BOM-ed的UTF-8字符串将以以下三个字节开始。Ef bb bf 如果存在这些字节,在从文件/流中提取字符串时必须忽略。

但是,作为附加信息,UTF-8的BOM可以很好地“嗅出”字符串是否以UTF-8编码……或者它可以是任何其他编码的合法字符串…

例如,数据[EF BB BF 41 42 43]可以是:

合法的ISO-8859-1字符串“ABC” 合法的UTF-8字符串“ABC”

因此,尽管通过查看第一个字节来识别文件内容的编码很酷,但您不应该依赖于此,如上面的示例所示

编码应该是已知的,而不是推测的。

Unicode字节顺序标记(BOM)常见问题解答提供了一个简明的答案:

Q: How I should deal with BOMs? A: Here are some guidelines to follow: A particular protocol (e.g. Microsoft conventions for .txt files) may require use of the BOM on certain Unicode data streams, such as files. When you need to conform to such a protocol, use a BOM. Some protocols allow optional BOMs in the case of untagged text. In those cases, Where a text data stream is known to be plain text, but of unknown encoding, BOM can be used as a signature. If there is no BOM, the encoding could be anything. Where a text data stream is known to be plain Unicode text (but not which endian), then BOM can be used as a signature. If there is no BOM, the text should be interpreted as big-endian. Some byte oriented protocols expect ASCII characters at the beginning of a file. If UTF-8 is used with these protocols, use of the BOM as encoding form signature should be avoided. Where the precise type of the data stream is known (e.g. Unicode big-endian or Unicode little-endian), the BOM should not be used. In particular, whenever a data stream is declared to be UTF-16BE, UTF-16LE, UTF-32BE or UTF-32LE a BOM must not be used.

没有BOM的UTF-8没有BOM,这并不意味着它比有BOM的UTF-8更好,除非文件的消费者需要知道(或者从知道中受益)文件是否是UTF-8编码的。

BOM通常用于确定编码的字节序,这对于大多数用例来说是不需要的。

此外,对于那些不了解或不关心BOM的消费者来说,BOM可能是不必要的噪音/痛苦,并可能导致用户困惑。

下面是一些实际导致问题的BOM使用示例,但许多人并不了解它。

BOM中断脚本

Shell脚本,Perl脚本,Python脚本,Ruby脚本,Node.js脚本或任何其他需要由解释器运行的可执行文件-都以shebang行开始,看起来像这样:

#!/bin/sh
#!/usr/bin/python
#!/usr/local/bin/perl
#!/usr/bin/env node

它告诉系统在调用这样的脚本时需要运行哪个解释器。如果脚本是用UTF-8编码的,人们可能会在开头包含一个BOM。但实际上“#!”字符不仅仅是字符。它们实际上是一个神奇的数字,恰好由两个ASCII字符组成。如果您在这些字符之前放了一些东西(如BOM),那么文件看起来就像有一个不同的魔法数字,这可能会导致问题。

参见维基百科,文章:Shebang,章节:魔法数字:

The shebang characters are represented by the same two bytes in extended ASCII encodings, including UTF-8, which is commonly used for scripts and other text files on current Unix-like systems. However, UTF-8 files may begin with the optional byte order mark (BOM); if the "exec" function specifically detects the bytes 0x23 and 0x21, then the presence of the BOM (0xEF 0xBB 0xBF) before the shebang will prevent the script interpreter from being executed. Some authorities recommend against using the byte order mark in POSIX (Unix-like) scripts,[14] for this reason and for wider interoperability and philosophical concerns. Additionally, a byte order mark is not necessary in UTF-8, as that encoding does not have endianness issues; it serves only to identify the encoding as UTF-8. [emphasis added]

BOM在JSON中是非法的

参见RFC 7159,章节8.1:

实现绝对不能在JSON文本的开头添加字节顺序标记。

BOM在JSON中是冗余的

它不仅在JSON中是非法的,而且也不需要确定字符编码,因为有更可靠的方法可以明确地确定任何JSON流中使用的字符编码和字节顺序(详细信息请参阅这个答案)。

BOM 会中断 JSON 解析器

它不仅在JSON中是非法的,而且不需要,它实际上破坏了所有使用RFC 4627中提出的方法来确定编码的软件:

确定JSON的编码和字节顺序,检查前四个字节为NUL字节:

00 00 00 xx - UTF-32BE
00 xx 00 xx - UTF-16BE
xx 00 00 00 - UTF-32LE
xx 00 xx 00 - UTF-16LE
xx xx xx xx - UTF-8

现在,如果文件以BOM开头,它将看起来像这样:

00 00 FE FF - UTF-32BE
FE FF 00 xx - UTF-16BE
FF FE 00 00 - UTF-32LE
FF FE xx 00 - UTF-16LE
EF BB BF xx - UTF-8

注意:

UTF-32BE不是以三个null开头的,所以它不会被识别 UTF-32LE第一个字节后面没有三个null,所以它不会被识别 UTF-16BE在前四个字节中只有一个NUL,所以它不会被识别 UTF-16LE在前四个字节中只有一个NUL,所以它不会被识别

根据实现的不同,所有这些都可能被错误地解释为UTF-8,然后被错误地解释或拒绝为无效的UTF-8,或者根本不被识别。

此外,如果实现像我推荐的那样测试有效的JSON,它甚至会拒绝确实编码为UTF-8的输入,因为它没有像RFC那样以< 128的ASCII字符开头。

其他数据格式

JSON格式的BOM是不需要的,是非法的,并且会破坏按照RFC正常工作的软件。当时不使用它应该是显而易见的,然而,总是有人坚持通过使用bom、注释、不同的引用规则或不同的数据类型来破坏JSON。当然,如果你需要,任何人都可以自由地使用像bom或其他东西——只是不要把它称为JSON。

对于JSON以外的其他数据格式,看看它到底是什么样子的。如果唯一的编码是UTF-*,并且第一个字符必须是小于128的ASCII字符,那么您已经拥有了确定数据编码和字节序所需的所有信息。即使将bom添加为可选特性,也只会使其更加复杂和容易出错。

BOM的其他用途

至于JSON或脚本之外的用途,我认为这里已经有了很好的答案。我想添加更详细的信息,特别是关于脚本和序列化,因为这是BOM字符导致实际问题的一个例子。