UTF-8 和不带 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,但是在从使用 BOM 的其他编码形式转换 UTF-8 数据或 BOM 用作 UTF-8 签名的情况下可能会遇到 BOM。 。有关更多信息请参见第 16.8 节特价 ” 中的 “字节顺序标记” 小节。

其他出色的答案已经回答:

  • UTF-8 和使用 BOM 的 UTF-8 之间没有官方区别
  • BOM 格式的 UTF-8 字符串将从以下三个字节开始。 EF BB BF
  • 从文件 / 流中提取字符串时,必须忽略那些字节(如果存在)。

但是,作为对此的附加信息,如果字符串以 UTF-8 编码,则 UTF-8 的 BOM 可能是 “嗅觉” 的好方法... 或者它可以是任何其他编码形式的合法字符串...

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

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

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

编码应该是已知的,而不是不可分割的。

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

  1. 不包含任何文本的文件不再为空,因为它们始终包含 BOM。
  2. 包含 UTF-8 ASCII 子集内的文本的文件本身不再是 ASCII,因为 BOM 不是 ASCII,这会使某些现有工具失效,并且用户无法替换这些旧版工具。
  3. 无法将多个文件连接在一起,因为现在每个文件的开头都有一个 BOM。

而且,正如其他人提到的那样,拥有 BOM 表来检测某物是否为 UTF-8 既不充分,也没有必要:

  • 这是不够的,因为任意字节序列可能会以构成 BOM 的确切序列开头。
  • 这是没有必要的,因为您可以读取字节,就像它们是 UTF-8 一样。如果成功,按照定义,它是有效的 UTF-8。

这是一个有很多好的答案的老问题,但应该增加一件事。

所有答案都很笼统。我要添加的是实际上会导致实际问题的 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,章节:幻数

shebang 字符由扩展 ASCII 编码中的相同两个字节表示,包括 UTF-8,该字符通常用于当前类 Unix 系统上的脚本和其他文本文件。但是,UTF-8 文件可以以可选的字节顺序标记(BOM)开头;如果 “exec” 功能专门检测到字节 0x23 和 0x21,则在 shebang 之前存在 BOM(0xEF 0xBB 0xBF)将阻止脚本解释器被执行。为此,一些权威人士建议不要在 POSIX(类 Unix)脚本中使用字节顺序标记,[14] 以及更广泛的互操作性和哲学问题。另外,在 UTF-8 中不需要字节顺序标记,因为该编码不存在字节顺序问题。它仅用于将编码标识为 UTF-8。 [重点添加]

BOM 在 JSON 中是非法的

参见RFC 7159 第 8.1 节

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

BOM 在 JSON 中是多余的

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

BOM 破坏了 JSON 解析器

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

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

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

注意:

  1. UTF-32BE 不是以三个 NUL 开头,因此不会被识别
  2. UTF-32LE 的第一个字节后没有 3 个 NUL,因此不会被识别
  3. UTF-16BE 的前 4 个字节只有 1 个 NUL,因此不会被识别
  4. UTF-16LE 的前 4 个字节只有 1 个 NUL,因此不会被识别

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

此外,如果实现按照我建议的那样测试有效的 JSON,则即使该输入确实被编码为 UTF-8,也将拒绝该输入,因为它不以 RFC 规定的 ASCII 字符 < 128 开头。

其他数据格式

不需要 JSON 中的 BOM,这是非法的,并且会破坏根据 RFC 正常运行的软件。只是不去使用它应该是明智的,但是,总是有人坚持使用 BOM,注释,不同的引用规则或不同的数据类型来破坏 JSON。当然,任何人都可以自由使用 BOM 或其他任何需要的东西 - 那就不要将其称为 JSON。

对于除 JSON 之外的其他数据格式,请看一下它的实际外观。如果唯一的编码是 UTF- *,并且第一个字符必须是小于 128 的 ASCII 字符,则您已经具有确定数据的编码和字节序所需的所有信息。即使将 BOM 表作为可选功能添加,也只会使其变得更加复杂且容易出错。

BOM 的其他用途

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

没有 BOM 的 UTF-8 和 UTF-8 有什么区别?

简短的答案:在 UTF-8 中,BOM 编码为文件开头的字节EF BB BF

长答案:

最初,预期Unicode将以 UTF-16 / UCS-2 编码。 BOM 是为此编码形式设计的。当您有 2 字节的代码单元时,有必要指出这两个字节的顺序,并且通常的惯例是在数据的开头包含字符 U + FEFF 作为 “字节顺序标记”。字符 U + FFFE 是永久未分配的,因此它的存在可用于检测错误的字节顺序。

无论平台的字节顺序如何,UTF-8 的字节顺序都相同,因此不需要字节顺序标记。但是,它可能会发生(作为字节序列EF BB FF )从 UTF-16 转换为 UTF-8 的数据中,或者作为 “签名” 表示该数据为 UTF-8。

哪个更好?

没有。正如 Martin Cote 回答的那样,Unicode 标准不建议这样做。它会导致非 BOM 感知软件出现问题。

检测文件是否为 UTF-8 的更好方法是执行有效性检查。 UTF-8 对有效的字节序列有严格的规定,因此误报的可能性可以忽略不计。如果字节序列看起来像 UTF-8,则可能是这样。

具有 BOM 的 UTF-8 可以更好地识别。我已经很难得出这个结论。我正在一个项目中,结果之一是一个CSV文件(包括 Unicode 字符)。

如果保存的 CSV 文件没有 BOM 表,则 Excel 会认为它是 ANSI 并显示乱码。一旦在前面添加了 “EF BB BF”(例如,通过使用带有 UTF-8 的记事本重新保存它;或带有 UTF-8 的 BOM 来保存记事本 ++),Excel 就会很好地打开它。

RFC 3629 建议将 BOM 表字符添加到 Unicode 文本文件中:“UTF-8,ISO 10646 的转换格式”,2003 年 11 月,位于http://tools.ietf.org/html/rfc3629 (此最新信息位于: http://www.herongyang.com/Unicode/Notepad-Byte-Order-Mark-BOM-FEFF-EFBBBF.html

BOM 倾向于在某个地方某个地方繁荣发展(无双关语)。而且当它蓬勃发展时(例如,未被浏览器,编辑器等识别),它会以奇怪的字符在文档的开头(例如,HTML 文件, JSON响应, RSS ,等),并导致这种尴尬,例如奥巴马在 Twitter 上的谈话中遇到最近编码问题

当它出现在难以调试的地方或忽略测试时,这很烦人。因此,除非您必须使用它,否则最好避免使用它。

问题:没有 BOM 的 UTF-8 和 UTF-8 有什么区别?哪个更好?

以下是 Wikipedia 文章中有关字节顺序标记(BOM)的一些摘录,我相信这些摘录可为该问题提供可靠的答案。

关于 BOM 和 UTF-8 的含义:

Unicode 标准允许使用UTF-8 中BOM ,但不要求也不建议使用它。字节顺序在 UTF-8 中没有任何意义,因此它在 UTF-8 中的唯一用途是在开始时发出信号,告知文本流已以 UTF-8 编码。

使用 BOM 的 参数

不使用 BOM 的主要动机是与不支持 Unicode 的软件向后兼容。另一个不使用 BOM 的动机是鼓励将 UTF-8 用作 “默认” 编码。

论据 使用 BOM:

使用 BOM 的理由是,如果没有 BOM,则需要进行启发式分析以确定文件正在使用的字符编码。从历史上看,这种区分各种 8 位编码的分析很复杂,容易出错,有时很慢。有许多库可以简化任务,例如 Mozilla 通用字符集检测器和 Unicode 国际组件。

程序员错误地认为检测 UTF-8 同样困难(这不是因为绝大多数字节序列都是无效的 UTF-8,而这些库试图区分的编码允许所有可能的字节序列)。因此,并非所有支持 Unicode 的程序都执行这种分析,而是依赖 BOM。

特别是, Microsoft编译器和解释器以及 Microsoft Windows 上的许多软件(例如记事本)将无法正确读取 UTF-8 文本,除非该文本只有 ASCII 字符或以 BOM 表开头,并且在保存时将 BOM 表添加到开头文字为 UTF-8。当将 Microsoft Word 文档下载为纯文本文件时,Google 文档将添加 BOM。

使用 BOM 表 使用 BOM 表 ,哪个更好

IETF建议,如果协议(a)始终使用 UTF-8,或(b)使用某种其他方式指示正在使用的编码,则该协议 “应禁止使用 U + FEFF 作为签名”。

我的结论:

当与软件应用程序的兼容性是绝对必要的时才使用 BOM。

还要注意,尽管参考的 Wikipedia 文章指出许多 Microsoft 应用程序都依赖 BOM 来正确检测 UTF-8,但并非所有 Microsoft 应用程序都如此。例如,如@barlop所指出的那样 ,当将 Windows 命令提示符与 UTF-8 †一起使用时 ,此类和more type命令不会希望 BOM 存在。如果 BOM 存在时,它可以是有问题的,因为它是用于其他应用。


chcp命令通过代码页65001提供对 UTF-8( BOM)的支持。

这个问题已经有一百万个答案了,其中许多都很好,但是我想尝试弄清楚何时应该使用或不应该使用 BOM。

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

如果找到对应于 UTF-8 BOM 的字节码,则概率很高,可以假定它是 UTF-8,您可以从那里继续。但是,当被迫做出这种猜测时,如果出现乱码,在读取时进行其他错误检查仍然是一个好主意。如果输入绝对不是基于源的 UTF-8,则只能假定 BOM 不是 UTF-8(即 latin-1 或 ANSI)。但是,如果没有 BOM,则可以通过对编码进行验证来简单地确定它是否应为 UTF-8。

为什么不建议使用 BOM?

  1. 不支持 Unicode 或兼容性不佳的软件可能会认为它是 latin-1 或 ANSI,并且不会从字符串中剥离 BOM,这显然会引起问题。
  2. 并不是真正需要的(只需检查内容是否符合要求,当找不到符合要求的编码时,始终使用 UTF-8 作为后备)

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

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

说到它,我真正真正遇到过的唯一文件是 CSV。根据程序,它要么必须具有 BOM,要么必须没有 BOM。例如,如果您在 Windows 上使用 Excel 2007+,则要平滑打开它而不必求助于导入数据,则必须使用 BOM 对其进行编码。

没有 BOM 的 UTF-8 没有 BOM,这不会比带有 BOM 的 UTF-8 更好,除非文件的使用者需要知道(或从中受益)文件是否经过 UTF-8 编码或不。

BOM 通常可用于确定编码的字节序,这在大多数使用情况下不是必需的。

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