UTF-8和UTF-8与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使用示例,但许多人并不了解它。

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

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

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

UTF-8与BOM更好地识别。我得出这个结论很不容易。我正在从事一个项目,其中一个结果是一个CSV文件,包括Unicode字符。

如果CSV文件保存时没有BOM, Excel会认为它是ANSI并显示胡言乱语。一旦你在前面添加了“EF BB BF”(例如,通过使用UTF-8记事本重新保存它;或notepad++与UTF-8与BOM), Excel打开它很好。

RFC 3629: "UTF-8,一种ISO 10646的转换格式",2003年11月建议将BOM字符前置到Unicode文本文件中 在https://www.rfc-editor.org/rfc/rfc3629(这最后的信息可以在:http://www.herongyang.com/Unicode/Notepad-Byte-Order-Mark-BOM-FEFF-EFBBBF.html)

如果你在HTML文件中使用UTF-8,如果你在同一页面上使用塞尔维亚西里尔语、塞尔维亚拉丁语、德语、匈牙利语或一些外来语言,那么使用UTF和BOM更好。

这是我(从事计算机和IT行业30年)的观点。

以下是我使用Visual Studio、Sourcetree和Bitbucket拉请求的经验,这给了我一些问题:

因此,在审查拉取请求时,带有签名的BOM将在每个文件上包含一个红点字符(这可能非常烦人)。

如果你把鼠标停在上面,它会显示一个像“ufeff”这样的字符,但事实证明Sourcetree不显示这些类型的字节标记,所以它很可能会在你的拉请求中结束,这应该是可以的,因为这是Visual Studio 2017现在编码新文件的方式,所以也许Bitbucket应该忽略这个或让它以另一种方式显示,更多信息在这里:

红点标记BitBucket差异视图