ChatGPT解决这个技术问题 Extra ChatGPT

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

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

UTF-8 可以通过内容比 BOM 更好地自动检测。方法很简单:尝试以 UTF-8 格式读取文件(或字符串),如果成功,则假定数据为 UTF-8。否则假定它是 CP1252(或其他一些 8 位编码)。任何非 UTF-8 八位编码几乎肯定会包含 UTF-8 不允许的序列。纯 ASCII(7 位)被解释为 UTF-8,但结果也是正确的。
扫描大文件中的 UTF-8 内容需要时间。 BOM 使这个过程更快。在实践中,您通常需要两者都做。现在的罪魁祸首是,仍然有很多文本内容不是 Unicode,而且我仍然遇到一些工具说它们使用 Unicode(例如 UTF-8),但将它们的内容发出不同的代码页。
@Tronic我真的不认为“更好”适合这种情况。这取决于环境。如果您确定所有 UTF-8 文件都标有 BOM,那么检查 BOM 是“更好”的方法,因为它更快、更可靠。
UTF-8 没有 BOM。当您将 U+FEFF 代码点放在 UTF-8 文件的开头时,必须特别注意处理它。这只是微软命名的谎言之一,就像在没有这样的东西时调用编码“Unicode”。
“现代大型机(和 AIX)支持小端 UTF-8” UTF-8 没有终结性!对于特定系统,没有任何字节混排来将四个对或四个组放入正确的“顺序”中!要检测 UTF-8 字节序列,请注意多字节序列“代码点”的第一个字节(不是“普通”ASCII 字节的字节)设置了 MS 位,并且还有一到三个连续较低的有效位后跟一个复位位。这些设置位的总数是该代码点中少一个字节,并且它们都将设置 MSB...

P
Peter Mortensen

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

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

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

2.6 编码方案 ... UTF-8 既不需要也不推荐使用 BOM,但在 UTF-8 数据从使用 BOM 的其他编码形式或 BOM 用作 UTF 的情况下可能会遇到-8 签名。有关详细信息,请参阅第 16.8 节“特价”中的“字节顺序标记”小节。


可能不建议这样做,但根据我在希伯来语转换方面的经验,BOM 有时对于 Excel 中的 UTF-8 识别至关重要,并且可能会在 Jibrish 和希伯来语之间产生差异
可能不推荐它,但它在尝试输出“æøå”时对我的 powershell 脚本产生了奇迹
不管标准不推荐它,它是允许的,我非常喜欢有一些东西作为 UTF-8 签名,而不是假设或猜测的替代方案。符合 Unicode 的软件应该/必须能够处理它的存在,所以我个人鼓励使用它。
@bames53:是的,在理想的世界中,将文本文件的编码存储为文件系统元数据将是保存它的更好方法。但是我们大多数生活在现实世界中的人都无法更改运行我们的程序的操作系统的文件系统——因此使用 Unicode 标准的平台独立 BOM 签名似乎是恕我直言的最佳和最实用的替代方案。
@martineau 就在昨天,我遇到了一个 UTF-8 BOM 不是 UTF-8(它是 CP936)的文件。不幸的是,那些对 UTF-8 BOM 造成的巨大痛苦负责的人在很大程度上没有注意到它。
P
Peter Mortensen

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

UTF-8 和 BOM-ed UTF-8 之间没有官方区别

一个 BOM-ed UTF-8 字符串将从以下三个字节开始。英法BB高炉

从文件/流中提取字符串时,必须忽略这些字节(如果存在)。

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

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

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

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

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

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


@Alcott:您理解正确。字符串 [EF BB BF 41 42 43] 只是一堆字节。您需要外部信息来选择如何解释它。如果您认为这些字节是使用 ISO-8859-1 编码的,那么字符串就是“ABC”。如果您认为这些字节是使用 UTF-8 编码的,那么它就是“ABC”。如果您不知道,那么您必须尝试找出答案。 BOM 可能是一个线索。解码为 UTF-8 时不存在无效字符可能是另一种情况……最后,除非您能以某种方式记住/找到编码,否则字节数组只是字节数组。
@paercebal虽然“”是有效的latin-1,但文本文件不太可能以该组合开头。这同样适用于 ucs2-le/be 标记 ÿþ 和 þÿ。你也永远无法知道。
@deceze这可能在语言上无效:首先是ï(可以),然后是一些引号之间没有空格(不行)。 ¿ 表示它是西班牙语,但 ï 在西班牙语中不使用。结论:它不是 latin-1,其确定性远高于没有它的确定性。
@user当然,这不一定有意义。但是,如果您的系统依赖于猜测,那就是不确定性的来源。一些恶意用户故意提交以这 3 个字母开头的文本,而您的系统突然假设它正在查看带有 BOM 的 UTF-8,将文本视为 UTF-8,其中它应该使用 Latin-1,并且会发生一些 Unicode 注入。只是一个假设的例子,但肯定有可能。您不能通过内容、句号来判断文本编码。
“编码应该是已知的,而不是预测的。”问题的核心和灵魂。 +1,好先生。换句话说:要么标准化你的内容,然后说,“我们一直在使用这种编码。期间。那样写。那样读,”或者开发一种扩展格式,允许将编码存储为元数据。 (后者可能也需要一些“引导标准编码”。就像说“告诉你编码的部分总是 ASCII。”)
j
jpsecher

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

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

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

这还不够,因为任意字节序列可能恰好以构成 BOM 的确切序列开头。

这不是必需的,因为您可以像读取 UTF-8 一样读取字节;如果成功,则根据定义,它是有效的 UTF-8。


关于第 1 点“不包含文本的文件不再为空,因为它们始终包含 BOM”,这 (1) 将 OS 文件系统级别与解释的内容级别混为一谈,此外 (2) 错误地假设使用 BOM 必须放置一个BOM 也在每个空文件中。 (1)的实际解决方案是不做(2)。从本质上讲,投诉减少到“可能不切实际地将 BOM 放入一个空文件中,从而阻止最容易检测到逻辑上的空文件(通过检查文件大小)”。仍然好的软件应该能够处理它,因为它有一个目的。
关于第 2 点,“包含 ASCII 文本的文件本身不再是 ASCII”,这将 ASCII 与 UTF-8 混为一谈。包含 ASCII 文本的 UTF-8 文件不是 ASCII,而是 UTF-8。同样,包含 ASCII 文本的 UTF-16 文件不是 ASCII,而是 UTF-16。等等。 ASCII 是一个 7 位的单字节代码。 UTF-8 是 ASCII 的 8 位可变长度扩展。如果“工具崩溃”由于 >127 个值,那么它们就不适用于 8 位世界。一种简单实用的解决方案是仅使用 ASCII 文件和分解非 ASCII 字节值的工具。一个可能更好的解决方案是抛弃那些不好的工具。
关于第 3 点,“不可能将多个文件连接在一起,因为现在每个文件的开头都有一个 BOM”是错误的。将 UTF-8 文件与 BOM 连接起来没有问题,所以这显然是可能的。我想也许你的意思是 Unix-land cat 不会给你一个 clean 结果,一个只在开始时有 BOM 的结果。如果你是这个意思,那是因为 cat 在字节级别工作,而不是在解释的内容级别,并且以类似的方式 cat 不能处理照片,比如说。仍然没有太大的伤害。这是因为 BOM 编码了一个零宽度的不间断空格。
@Cheersandhth.-Alf 这个答案是正确的。您只是在指出 Microsoft 的错误。
@brighty:尽管添加了一个 bom,但情况并没有得到任何改善。
C
Community

以下是实际导致实际问题但许多人不知道的 BOM 用法示例。

BOM 中断脚本

Shell 脚本、Perl 脚本、Python 脚本、Ruby 脚本、Node.js 脚本或任何其他需要由解释器运行的可执行文件 - 都以 shebang line 开头,类似于以下内容之一:

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

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

参见维基百科,article: Shebang, section: Magic number

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, Section 8.1

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

BOM 在 JSON 中是多余的

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

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 不以三个 NUL 开头,所以不会识别 UTF-32LE 第一个字节后面没有三个 NUL,所以不会识别 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 字符导致实际问题的一个示例。


取代 rfc4627 的 rfc7159 实际上表明支持 BOM 可能不是那么邪恶。基本上没有 BOM 只是一个模棱两可的问题,因此不支持 Unicode 的旧 Windows 和 Unix 软件仍然可以处理 utf-8。
听起来 JSON 需要更新才能支持它,Perl 脚本、Python 脚本、Ruby 脚本、Node.js 也是如此。仅仅因为这些平台选择不包括支持,并不一定会扼杀对 BOM 的使用。几年来,苹果一直试图杀死 Adobe,而 Adobe 仍然存在。但是一个启发性的帖子。
@EricGrange,您似乎非常强烈地支持 BOM,但没有意识到这将使无处不在、普遍有用、最优最小的“纯文本”格式成为 UTF8 之前的过去的遗物!根据定义,将任何类型的(带内)标头添加到纯文本流中,将对最简单的文本文件强加一个强制性协议,使其不再是“最简单的”!为了什么收获?为了支持所有其他也没有签名的古老 CP 编码,所以您可能会将它们误认为 UTF-8? (顺便说一句,ASCII 也是 UTF-8。那么,这些也是 BOM 吗?;)来吧。)
这个答案就是我提出这个问题的原因!我在 Windows 中创建我的 bash 脚本,在将这些脚本发布到 Linux 时遇到了很多问题!与 jason 文件相同。
我希望我能给这个答案投票大约五十次。我还想补充一点,在这一点上,UTF-8 已经赢得了标准大战,并且几乎所有在 Internet 上生成的文本都是 UTF-8。一些最流行的编程语言(例如 C# 和 Java)在内部使用 UTF-16,但是当使用这些语言的程序员将文件写入输出流时,他们几乎总是将它们编码为 UTF-8。因此,用 BOM 标记 UTF-8 文件不再有意义; UTF-8 应该是你在阅读时使用的默认编码,只有在 UTF-8 解码失败时才尝试其他编码。
P
Peter Mortensen

UTF-8 和没有 BOM 的 UTF-8 有什么不同?

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

长答案:

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

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

哪个更好?

没有。正如 Martin Cote 所回答的,Unicode 标准不推荐它。它会导致非 BOM 感知软件出现问题。

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


不过,这也会使包含单个错误字节的有效 UTF-8 无效:/
-1 re“它会导致不支持 BOM 的软件出现问题。”,这对我来说从来都不是问题,但相反,缺少 BOM 会导致支持 BOM 的软件(尤其是 Visual C++)出现问题。问题。所以这个陈述是非常特定于平台的,是一个狭隘的 Unix 领域的观点,但被误导了,就好像它普遍适用一样。它没有。
不,UTF-8 没有 BOM。这个答案是不正确的。请参阅 Unicode 标准。
仅查看字节时,您甚至可以认为您有一个纯 ASCII 文件。但这也可能是一个 utf-16 文件,您必须在其中查看单词而不是字节。现代软件应该了解 BOM。如果检测到无效序列、可以使用较小序列的代码点或代理代码点,仍然读取 utf-8 可能会失败。对于 utf-16,当存在孤立代理时,读取也可能会失败。
@Alf,我不同意您将非 BOM 态度解释为“特定于平台的,一种狭隘的 Unix 领域观点”。对我来说,“Unix 领域”的狭隘思想的唯一方式是 MS 和 Visual C++ 出现在 *NIX 之前,而他们没有。 MS(我故意假设)开始使用 UTF-8 而不是 UTF-16 的 BOM 的事实向我表明,他们提倡破坏 shperlg++ 和许多其他免费且强大的工具。想让事情奏效吗?只需购买 MS 版本。 MS 造成了特定于平台的问题,就像他们的 \x80-\x95 范围的灾难一样。
C
Community

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

如果 CSV 文件在没有 BOM 的情况下保存,Excel 会认为它是 ANSI 并显示乱码。在前面添加“EF BB BF”后(例如,通过使用带有 UTF-8 的记事本重新保存它;或使用带有 BOM 的 UTF-8 的 Notepad++ 重新保存它),Excel 可以正常打开它。

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


感谢这个出色的提示,以防万一创建供 Excel 使用的 UTF-8 文件。但在其他情况下,我仍然会遵循其他答案并跳过 BOM。
如果您创建的文件仅包含 ASCII 并且以后可能添加了非 ASCII,这也很有用。我刚刚遇到了这样一个问题:需要 utf8 的软件会创建包含一些数据的文件以供用户编辑。如果初始文件仅包含 ASCII,在某些编辑器中打开然后保存,它会以 latin-1 结尾,一切都会中断。如果我添加 BOM,它会被编辑器检测为 UTF8,一切正常。
我发现了多个需要 BOM 才能正确识别 UTF-8 文件的编程相关工具。 Visual Studio、SSMS、SoureTree……
您在哪里阅读了在该 RFC 中使用 BOM 的建议?最多,强烈建议不要在某些情况下禁止它,因为这样做很困难。
Excel 认为它是 ANSI 并显示乱码,然后问题出在 Excel 中。
D
DavidRR

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

以下是关于 byte order mark (BOM) 的 Wikipedia 文章的一些摘录,我相信这些文章可以为这个问题提供可靠的答案。

关于 BOM 和 UTF-8 的含义:

Unicode 标准允许使用 UTF-8 的 BOM,但不要求也不推荐使用它。字节顺序在 UTF-8 中没有任何意义,因此它在 UTF-8 中的唯一用途是在开始时表示文本流以 UTF-8 编码。

不使用 BOM 的论据:

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

使用 BOM 的参数:

使用 BOM 的理由是,如果没有它,则需要启发式分析来确定文件使用的字符编码。从历史上看,为了区分各种 8 位编码,这种分析是复杂的、容易出错的,而且有时速度很慢。许多库可用于简化任务,例如 Mozilla Universal Charset Detector 和 International Components for Unicode。程序员错误地认为 UTF-8 的检测同样困难(这并不是因为绝大多数字节序列都是无效的 UTF-8,而这些库试图区分的编码允许所有可能的字节序列)。因此,并非所有支持 Unicode 的程序都执行此类分析,而是依赖 BOM。特别是 Microsoft 编译器和解释器,以及 Microsoft Windows 上的许多软件(例如记事本)将无法正确读取 UTF-8 文本,除非它只有 ASCII 字符或以 BOM 开头,并且在保存时会在开头添加 BOM文本为 UTF-8。当 Microsoft Word 文档作为纯文本文件下载时,Google Docs 将添加 BOM。

哪个更好,有或没有 BOM:

IETF 建议,如果一个协议 (a) 始终使用 UTF-8,或者 (b) 有其他方式来指示正在使用什么编码,那么它“应该禁止使用 U+FEFF 作为签名”。

我的结论:

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

另请注意,虽然引用的 Wikipedia 文章表明许多 Microsoft 应用程序依赖 BOM 来正确检测 UTF-8,但对于 所有 Microsoft 应用程序而言并非如此。例如,正如 @barlop 所指出的,当使用带有 UTF-8 的 Windows 命令提示符时,诸如 typemore 之类的命令预计不会出现 BOM。如果 BOM 存在,则可能会出现问题,因为它对于其他应用程序也是如此。

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


我最好严格没有BOM。我发现 .htaccessgzip compression 与 UTF-8 BOM 结合使用会出现编码错误 更改为不带 BOM 的 UTF-8 编码遵循here 中解释的建议解决问题
“不使用 BOM 的另一个动机是鼓励将 UTF-8 作为“默认”编码。 - 这是一个如此强大和有效的论点,你实际上可以在那里停止答案!... ;-o 除非你对通用文本表示有更好的想法,那就是。 ;) (我不知道你多大了,在 UTF8 之前的时代(当时语言学家拼命考虑甚至改变他们的字母表)你不得不受苦多少年,但我可以告诉你,我们每一秒都在接近摆脱所有古老的单字节无元数据编码的混乱,而不是拥有“那个”是纯粹的快乐。)
另请参阅 this comment,了解如何将 BOM(或任何内容!)添加到最简单的文本文件格式“纯文本”中,这意味着完全防止 最佳通用文本编码格式成为“纯文本” ”和“简单”(即“无开销”)!...
BOM 在 Linux 上主要是个问题,因为许多实用程序一开始并不真正支持 Unicode(例如,它们很乐意在代码点中间截断)。对于大多数其他现代软件环境,只要编码不是明确的(通过规范或元数据),就使用 BOM。
P
Peter Mortensen

BOM 往往会在某处某处繁荣(没有双关语(原文如此))。当它繁荣时(例如,浏览器、编辑器等无法识别),它会在文档开头显示为奇怪的字符 (例如,HTML 文件、JSON 响应、 RSS 等)并导致像 recent encoding issue experienced during the talk of Obama on Twitter 这样的尴尬。

当它出现在难以调试的地方或忽略测试时,这是非常烦人的。所以最好避免它,除非你必须使用它。


是的,只是花了几个小时来确定由文件编码为 UTF-8 而不是没有 BOM 的 UTF-8 引起的问题。 (这个问题只出现在 IE7 中,这让我大吃一惊。我使用了 Django 的“包含”。)
未来的读者:请注意,我上面提到的推文问题与 BOM 没有严格的关系,但如果是,那么推文将以类似的方式出现乱码,但在推文的开头。
@user984003 不,问题是微软误导了你。它所谓的 UTF-8 不是 UTF-8。它所谓的没有 BOM 的 UTF-8 就是 UTF-8 的真正含义。
“原文如此”在您的“没有双关语”中添加了什么
@JoelFan 我不记得了,但我猜双关语可能是有意的,尽管作者声称:)
P
Peter Mortensen

这个问题已经有一百万个答案,其中许多都很好,但我想尝试澄清何时应该或不应该使用 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?

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

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

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

归根结底,我真正遇到问题的唯一文件是 CSV。根据程序,它必须或不能有 BOM。例如,如果您在 Windows 上使用 Excel 2007+,如果您想顺利打开它并且不必求助于导入数据,则必须使用 BOM 对其进行编码。


您答案的最后一部分是 100% 正确的:使用 BOM 的唯一原因是当您必须与不使用 UTF-8 作为默认值来解析未知文件的错误软件进行互操作时。
R
Romain

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

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

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


“这对 UTF-8 没有用,因为它是每个字形 8 位。”呃......不,只有 ASCII-7 字形在 UTF-8 中是 8 位的。除此之外的任何内容都将是 16、24 或 32 位。
“BOM 通常可用于确定编码的字节顺序,这对于大多数用例来说不是必需的。”...字节顺序根本不适用于 UTF-8,无论用例如何
需要知道的消费者被设计破坏了。
D
Deduplicator

应该注意的是,对于某些文件,即使在 Windows 上,您也不得具有 BOM。例如 SQL*plusVBScript 文件。如果此类文件包含 BOM,则在尝试执行它们时会出现错误。


p
pib

在 BOM 的 Wikipedia 页面底部引用:http://en.wikipedia.org/wiki/Byte-order_mark#cite_note-2

“对于 UTF-8 既不需要也不建议使用 BOM,但在 UTF-8 数据从使用 BOM 的其他编码形式转换或 BOM 用作 UTF-8 签名的情况下可能会遇到”


您是否有任何示例软件根据之前的编码是否具有 BOM 来决定是否使用带/不带 BOM 的 UTF-8?!这似乎是一个荒谬的主张
P
Peter Mortensen

仅当文件实际上包含一些非 ASCII 字符时,带有 BOM 的 UTF-8 才有帮助。如果它被包含并且没有,那么它可能会破坏旧的应用程序,否则这些应用程序会将文件解释为纯 ASCII。这些应用程序在遇到非 ASCII 字符时肯定会失败,所以在我看来,只有在文件可以而且应该不再被解释为纯 ASCII 时才应该添加 BOM。

我想明确表示我更喜欢根本没有 BOM。如果一些旧的垃圾在没有它的情况下会损坏,请添加它,并且替换该遗留应用程序是不可行的。

不要期望 UTF-8 的 BOM。


不确定非 UTF8 感知的应用程序在遇到 UTF8 时是否会失败,UTF8 的全部意义在于许多事情都可以正常工作 wc(1) 将给出正确的行数和八位字节数,如果没有 unicode-only 则给出正确的字数使用空格字符。
我同意你的看法@Jasen。如果我只是删除这个旧答案,我会尝试锻炼。我目前的观点是,答案就是不添加 BOM。如果最终用户必须破解文件以使其与旧软件一起使用,他们可以附加一个。我们不应该制作使这种不正确行为永久存在的软件。没有理由文件不能以零宽度非连接符开始,该零宽度非连接符被解释为一。
C
Community

我从不同的角度看待这个问题。我认为带有 BOM 的 UTF-8 更好,因为它提供了有关文件的更多信息。仅当我遇到问题时,我才使用没有 BOM 的 UTF-8。

我在我的页面上使用多种语言(甚至 Cyrillic)很长一段时间,当文件在没有 BOM 的情况下保存并且我重新打开它们以使用编辑器进行编辑(如 cherouvim 也指出)时,某些字符已损坏.

请注意,当您尝试使用 UTF-8 编码保存新创建的文件时,Windows 的经典 Notepad 会自动使用 BOM 保存文件。

我个人用 BOM 保存服务器端脚本文件(.asp、.ini、.aspx)和不带 BOM 的 .html 文件。


感谢您提供有关 Windows 经典记事本的出色提示。我已经花了一些时间找出完全相同的东西。我的结果是始终使用 Notepad++ 而不是 Windows 经典记事本。 :-)
你最好使用madedit。它是唯一的编辑器 - 在十六进制模式下 - 如果您选择 utf-8 字节序列而不是字节和字符之间的 1:1 基础,则显示一个字符。一个知道 UTF-8 文件的十六进制编辑器应该像 madedit 一样倾斜!
@brighty 我认为您不需要为了 BOM 而一对一。没关系,识别 utf-8 BOM 是 efbbbf 或 fffe 并不需要太多(如果读错了 fffe)。可以简单地删除这些字节。虽然对文件的其余部分进行映射也不错,但也可以逐字节删除
@barlop 如果文件的内容是 utf-8 编码的,为什么要删除 utf-8 BOM? BOM 被现代文本查看器、文本控件以及文本编辑器识别。 utf-8 序列的一对一视图没有意义,因为 n 个字节产生一个字符。当然,文本编辑器或十六进制编辑器应该允许删除任何字节,但这会导致无效的 utf-8 序列。
@brighty 带有 bom 的 utf-8 是一种编码,而没有 bom 的 utf-8 是一种编码。 cmd 提示符使用不带 bom 的 utf8。因此,如果您有一个 utf8 文件,则运行命令 chcp 65001 以获得 utf8 支持,它是不带 bom 的 utf8。如果您执行 type myfile,它只会在没有 bom 的情况下正确显示。如果您执行 echo aaa>a.aecho אאא>a.a 将字符输出到文件 aa,并且您有 chcp 65001,它将输出没有 BOM。
P
Peter Mortensen

当您想显示以 UTF-8 编码的信息时,您可能不会遇到问题。例如,将 HTML 文档声明为 UTF-8,您将在浏览器中显示包含在文档正文中的所有内容。

但当我们在 Windows 或 Linux 上拥有文本、CSV 和 XML 文件时,情况就不是这样了。

例如,Windows 或 Linux 中的文本文件是可以想象的最简单的事情之一,它(通常)不是 UTF-8。

将其保存为 XML 并将其声明为 UTF-8:

<?xml version="1.0" encoding="UTF-8"?>

它不会正确显示(不会被读取),即使它被声明为 UTF-8。

我有一串包含法语字母的数据,需要将其保存为 XML 以进行联合。无需从一开始就创建 UTF-8 文件(更改 IDE 中的选项和“创建新文件”)或在文件开头添加 BOM

$file="\xEF\xBB\xBF".$string;

我无法将法语字母保存在 XML 文件中。


我知道这是一个旧答案,但我只想提一下这是错误的。 Linux 上的文本文件(不能代表其他 Unix)通常是 /are/ UTF-8。
P
Peter Mortensen

一个实际的区别是,如果您为 Mac OS X 编写一个 shell 脚本并将其保存为纯 UTF-8,您将得到响应:

#!/bin/bash: No such file or directory

响应 shebang 行,指定您希望使用的外壳:

#!/bin/bash

如果您保存为 UTF-8,则没有 BOM(例如在 BBEdit 中)一切都会好起来的。


那是因为微软已经改变了标准所说的含义。 UTF-8 没有 BOM:他们创建了 Microsoft UTF-8,它在数据流前面插入了一个虚假的 BOM,然后告诉你不,这实际上是 UTF-8。它不是。它只是在扩展和破坏。
W
Wernfried Domscheit

Unicode Byte Order Mark (BOM) FAQ 提供了一个简洁的答案:

问:我应该如何处理 BOM?答:以下是一些需要遵循的准则: 特定协议(例如 Microsoft 对 .txt 文件的约定)可能需要在某些 Unicode 数据流(例如文件)上使用 BOM。当您需要遵守此类协议时,请使用 BOM。某些协议允许在未标记文本的情况下使用可选的 BOM。在那些情况下,如果已知文本数据流是纯文本,但编码未知,则 BOM 可用作签名。如果没有 BOM,则编码可以是任何东西。如果已知文本数据流是纯 Unicode 文本(但不是哪个字节序),则 BOM 可用作签名。如果没有 BOM,则应将文本解释为大端。一些面向字节的协议要求在文件开头使用 ASCII 字符。如果 UTF-8 与这些协议一起使用,则应避免使用 BOM 作为编码形式签名。如果数据流的精确类型已知(例如 Unicode big-endian 或 Unicode little-endian),则不应使用 BOM。特别是,当数据流被声明为 UTF-16BE、UTF-16LE、UTF-32BE 或 UTF-32LE 时,不得使用 BOM。


P
Peter Mortensen

如上所述,带有 BOM 的 UTF-8 可能会导致非 BOM 感知(或兼容)软件出现问题。我曾经使用基于 Mozilla 的 KompoZer 编辑编码为 UTF-8 + BOM 的 HTML 文件,因为客户端需要该 WYSIWYG 程序。

保存时布局总是会被破坏。我花了一些时间来解决这个问题。这些文件随后在 Firefox 中运行良好,但在 Internet Explorer 中显示了一个 CSS 怪癖,再次破坏了布局。在摆弄链接的 CSS 文件数小时无济于事后,我发现 Internet Explorer 不喜欢 BOMfed HTML 文件。再也不。

另外,我刚刚在维基百科中找到了这个:

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


P
Peter Mortensen

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,这会导致后续开发链中的其他问题。


确保虚假字节出现在非 BOM 感知软件的开头。耶。
@Romain Muller:例如,当您尝试在 BOM 之后发送标头时,PHP 5 将抛出“不可能的”错误。
αβγ 不是 ascii,但可以出现在基于 8bit-ascii 的编码中。使用 BOM 会禁用 utf-8 的好处,它与 ascii 的兼容性(与使用纯 ascii 的旧应用程序一起工作的能力)。
这是错误的答案。前面有 BOM 的字符串完全是另外一回事。它不应该在那里,只是把一切都搞砸了。
如果没有 BOM,它将在大多数编辑器中以 ANSI 形式打开。我完全同意。如果发生这种情况,如果您处理了正确的代码页,那么您很幸运,但实际上这只是一个猜测,因为代码页不是文件的一部分。 BOM 是。
P
Peter Mortensen

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

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

https://i.stack.imgur.com/74jjy.png

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

Red dot marker BitBucket diff view


G
Good Pen

我用 utf-8 保存了一个自动热键文件,中文字符变得奇怪。

使用 utf-8 BOM,工作正常。

AutoHotkey 不会自动识别 UTF-8 文件,除非它以字节顺序标记开头。

https://www.autohotkey.com/docs/FAQ.htm#nonascii


P
Peter Mortensen

如果您在 HTML 文件中使用 UTF-8,并且如果您在同一页面上使用塞尔维亚西里尔文、塞尔维亚拉丁文、德语、匈牙利语或某些异国语言,则带有 BOM 的 UTF 会更好。

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


我也觉得这是真的。如果您使用第一个 255 ASCII 集之外的字符并省略 BOM,浏览器会将其解释为 ISO-8859-1,您会得到乱码。鉴于上述答案,这显然是浏览器供应商在未检测到 BOM 时做错了事情。但除非你在 Microsoft Edge/Mozilla/Webkit/Blink 工作,否则你别无选择,只能处理这些应用程序的缺陷。
UTF 什么? UTF-8? UTF-16?还有什么?
如果您的服务器没有指示正确的 mime 类型字符集参数,您应该在 HTML 标头中使用 <meta http-equiv 标记。