UTF-8和UTF-8与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字符导致实际问题的一个例子。

其他回答

这个问题已经有了无数个答案,其中许多答案都很好,但我想尝试并澄清何时应该使用BOM,何时不应该使用BOM。

如前所述,任何使用UTF BOM(字节顺序标记)来确定字符串是否为UTF-8的方法都是有根据的猜测。如果有适当的元数据可用(如charset="utf-8"),那么您已经知道应该使用什么,但除此之外,您还需要进行测试并做出一些假设。这涉及到检查字符串来自的文件是否以十六进制字节码EF BB BF开头。

If a byte code corresponding to the UTF-8 BOM is found, the probability is high enough to assume it's UTF-8 and you can go from there. When forced to make this guess, however, additional error checking while reading would still be a good idea in case something comes up garbled. You should only assume a BOM is not UTF-8 (i.e. latin-1 or ANSI) if the input definitely shouldn't be UTF-8 based on its source. If there is no BOM, however, you can simply determine whether it's supposed to be UTF-8 by validating against the encoding.

为什么不推荐使用BOM ?

不支持unicode或兼容性较差的软件可能会假定它是latin-1或ANSI,并且不会从字符串中剥离BOM,这显然会导致问题。 这并不是真正需要的(只要检查内容是否兼容,并且在找不到兼容编码时总是使用UTF-8作为备用)

什么时候应该使用BOM编码?

如果您无法以任何其他方式(通过字符集标记或文件系统元)记录元数据,并且像使用BOM一样使用程序,则应该使用BOM进行编码。在Windows上尤其如此,没有BOM的任何东西通常都被认为使用了遗留代码页。BOM告诉Office等程序,是的,这个文件中的文本是Unicode;这是使用的编码。

归根结底,我唯一真正有问题的文件是CSV。根据程序的不同,它必须或必须没有BOM。例如,如果你在Windows上使用Excel 2007+,如果你想要顺利地打开它,而不必求助于导入数据,它必须用BOM编码。

引用于维基百科页面底部BOM: http://en.wikipedia.org/wiki/Byte-order_mark#cite_note-2

对于UTF-8,使用BOM既不要求也不推荐,但在从使用BOM的其他编码形式转换UTF-8数据或将BOM用作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节特殊项中的“字节顺序标记”小节。

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.

从http://en.wikipedia.org/wiki/Byte-order_mark:

字节顺序标记(BOM)是一个Unicode 符号的符号 文本文件的字节顺序 或流。其编码点为U+FEFF。 BOM使用是可选的,如果使用, 应该出现在文本的开头吗 流。除了它的特殊用途 字节顺序指示器,即BOM 字符也可以指示哪一个 几种Unicode表示 文本是用。

总是在文件中使用BOM将确保它总是在支持UTF-8和BOM的编辑器中正确打开。

我对缺少BOM的真正问题如下。假设我们有一个文件,它包含:

abc

如果没有BOM,在大多数编辑器中它会作为ANSI打开。所以这个文件的另一个用户打开它,并添加一些本机字符,例如:

abg-αβγ

哎呀……现在文件仍然在ANSI中,你猜怎么着,“αβγ”不占用6个字节,而是3个字节。这不是UTF-8,这会在开发链的后面引起其他问题。