Mar*_*ote 738

UTF-8 BOM是文本流(EF BB BF)开头的字节序列,允许读者更可靠地猜测文件是否以UTF-8编码.

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

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

2.6编码方案

...对于UTF-8既不要求也不建议使用BOM,但在使用BOM的其他编码形式或将BOM用作UTF-8签名的UTF-8数据转换的上下文中可能会遇到.有关详细信息,请参见第16.8节 " 特价 "中的"字节顺序标记"小节.

  • 可能不推荐,但根据我在希伯来语转换方面的经验,BOM有时对于Excel中的UTF-8识别至关重要,并且可能区别于Jibrish和希伯来语 (105认同)
  • 无论它是否被标准推荐,都是允许的,我更喜欢有一些东西作为UTF-8签名而不是假设或猜测的替代方案.符合Unicode的软件应该/必须能够处理它的存在,所以我个人鼓励使用它. (57认同)
  • @ bames53:是的,在理想的世界中,将文本文件的编码存储为文件系统元数据将是更好的方法来保存它.但是我们生活在现实世界中的大多数人都无法改变我们的程序运行的操作系统的文件系统 - 所以使用Unicode标准的独立于平台的BOM签名似乎是最好和最实用的替代恕我直言. (27认同)
  • @martineau就在昨天,我遇到了一个UTF-8 BOM的文件,它不是UTF-8(它是CP936).不幸的是,由UTF-8物料清单导致的巨大痛苦的负责人基本上没有注意到它. (27认同)
  • 它可能不推荐,但在尝试输出"æøå"时,它对我的​​powershell脚本产生了奇迹 (22认同)
  • @martineau还有另一种猜测和假设的选择:正确存储编码元数据.UTF-8 BOM是一个hacky尝试,但由于这个元数据存储在主数据流中,它实际上相当于猜测.例如,没有任何内容表明我的ISO 8859-1编码纯文本文件不能以字符""开头,这与UTF-8 BOM无法区分.指示纯文本文件编码的适当方式是,例如,文件系统属性. (14认同)
  • 我不是这里的最后一句话,但我认为你正在解释标准 - 在非正式意义上说话.对于标准机构_recommend_某事,这意味着他们正式做出首选用法的规范性指示.不建议的是明确不提供意见."既不要求也不推荐"并不意味着Unicode标准建议您不要对UTF-8文件使用UTF-8签名 - 这只是意味着他们没有采用某种方式. (11认同)
  • @martineau NTFS支持任意文件属性,Linux和OS X使用的文件系统也是如此.事实上,OS X使用扩展属性进行文本编码,并且有一个方案可以保存这些属性,即使在本机不支持它们的文件系统上也是如此,例如FAT32和内部zip文件.BOM并不是一个更实用的解决方案,因为它是一个愚蠢的(它仍然只是猜测,毕竟)具有病毒属性,让它建立了很多惯性. (9认同)
  • 另请注意,Windows似乎默认使用BOM表示UTF-8,并且许多Microsoft程序不尝试启发式检测,因此如果缺少BOM,则无法正确解码文件. (6认同)
  • @ barnes53 - 文件系统属性不适用于以BOM开头的HTTP请求或响应.(这种情况实际上是让我想到这个问题的原因.) (5认同)
  • @ bames53:每个操作系统都有不同的方式来访问和解释元数据,这是一种只能预期会继续下去并且可能在将来变得更糟的情况.使用utf-8 BOM可能在技术上是猜测,但实际上它对于文本文件来说不太可能是错误的.显然,我们的意见在"实际"含义上有所不同...... (4认同)
  • BOM应该被认为是强制性的,不推荐是Unicode标准的主要缺陷之一,并且可能是这些年后utf-8仍然存在问题的主要原因. (4认同)
  • @EricGrange - 您的评论让我怀疑您从未遇到过 UTF-8 BOM 可能导致的许多问题。通过连接字符串来构建输出是很常见的;如果这些字符串是用 BOM 编码的,那么您现在在输出中间有一个 BOM。而这只是问题的开始。不需要在 UTF-8 中指定字节顺序,并且使用 BOM 作为编码检测器是有问题的 [其他原因](http://stackoverflow.com/questions/2223882/whats-different-between-utf-8 -and-utf-8-without-bom#comment31878569_2223926)。 (4认同)
  • @Matanya 关于 Excel,这是微软的产品(也不推荐微软)。有时,当做一些不推荐的事情时,就有必要做一些不推荐的事情。标准中说明有时会遇到 BOM 的段落是作为对 Microsoft 使用 BOM 的回应而添加的。 (3认同)
  • @martineau实际上,在理想的世界中,每个文件都应该具有预定义字节长度的唯一签名,包括文本文件(每个编码一个).这样,启发式就没有必要了.就像在具有内容类型的HTTP协议中一样. (3认同)
  • +rmunn 您描述的问题实际上很容易解决,因为 BOM 是一个没有其他含义的特殊序列,始终具有 BOM 不会引入歧义,因为它可以安全地检测到。另一方面,没有 BOM 的存储字符串只能通过元数据和约定知道是 UTF-8。两者都很脆弱,文件系统在两者上都明显失败,因为唯一的元数据通常是文件扩展名,它只是松散地暗示内容编码。强制 BOM 实施可以 100% 安全,没有 BOM,只有猜测和祈祷...... (3认同)
  • 我发现一些编码检测库只能在存在 BOM 时正确猜测 UTF-8。否则,启发式方法似乎不是 100% 准确的。 (2认同)
  • @GarretWilson我同意您的解释,即*这仅表示他们没有采取任何立场。*但这也意味着,包括解决任何实际问题的BOM至少是多余的。并带来一些有害的不良后果。[至少这个](http://stackoverflow.com/a/13398447/6843677)。 (2认同)
  • @EricGrange UTF-8 BOM确实有一个严重的问题,尽管这个问题实际上并不是由BOM本身引起的.也就是说,由于它既不需要也不推荐,但是有大量的代码可以处理没有BOM的UTF-8,而是在BOM本身上产生扼流圈.因此,由于这个已知问题,他们很可能不会推荐它,但问题是由于它不被推荐而引起的,实际上是一个自给自足的循环. (2认同)

pae*_*bal 229

其他优秀的答案已经回答:

  • UTF-8和BOM-ed UTF-8之间没有官方差异
  • BOM编辑的UTF-8字符串将以以下三个字节开头. EF BB BF
  • 从文件/流中提取字符串时,必须忽略这些字节(如果存在).

但是,作为附加信息,如果字符串是以UTF-8编码的话,UTF-8的BOM可能是一种"闻"的好方法......或者它可能是任何其他编码中的合法字符串......

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

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

编码应该是已知的,而不是神圣的.

  • @Alcott:你理解正确.字符串[EF BB BF 41 42 43]只是一堆字节.您需要外部信息来选择如何解释它.如果您认为这些字节是使用ISO-8859-1编码的,则字符串为"ABC".如果您认为这些字节是使用UTF-8编码的,那么它就是"ABC".如果您不知道,那么您必须尝试找出答案.BOM可能是一个线索.解码为UTF-8时缺少无效字符可能是另一个......最后,除非你能以某种方式记忆/找到编码,否则字节数组只是一个字节数组. (56认同)
  • **"编码应该是已知的,而不是神圣的."**问题的核心和灵魂.+1,好先生.换句话说:要么标准化你的内容并说"我们总是使用这种编码.期间.按照这种方式写.以这种方式读取",或者开发一种允许将编码存储为元数据的扩展格式.(后者可能也需要一些"引导标准编码".就像说"告诉你编码的部分总是ASCII.") (38认同)
  • @user当然,它不一定有道理.但是如果你的系统依赖于*猜测*,那就是不确定性的来源.有些恶意用户故意提交以这3个字母开头的文本,而你的系统突然假设它正在查看带有BOM的UTF-8,将文本视为UTF- 8它应该使用Latin-1,并进行一些Unicode注入.只是一个假设的例子,但肯定是可能的.您无法通过其内容,句点来判断文本编码. (18认同)
  • @paercebal虽然""是有效的latin-1,但文本文件以该组合开头是不太可能的*.对于ucs2-le/be标记ÿþ和The也是如此.你也可以*永远*知道. (17认同)
  • @deceze它可能在语言上无效:第一个ï(可以),然后是一些没有空格的引号(不好).¿表示它是西班牙语,但ï不用于西班牙语.结论:如果没有它,确定性不高于latin-1. (14认同)
  • @user确实,*非常不可能*,但*完全有效.*你不能说它不是*拉丁-1,100%确定. (5认同)
  • @user不,你没有.但我是说如果你看一下字符串的内容来确定它的编码,就有可能你会遇到奇怪的情况.例如,您的系统可能无法正确接受以字符""开头的Latin-1文件.虽然这种情况发生的可能性很小(我不是在争论),但它仍然是*可能性*.而且我更喜欢写*正确*代码而不是代码*如果...*可能会破坏. (5认同)
  • 抱歉,先生,但我不太明白你刚才给出的例子.如果我有一个字符串[EF BB BF 41 42 43],我怎么能解释它?使用ISO-8859-1或UTF-8?因为正如你的例子所说,两者都会给出一个合法的字符串:"ABC"和"ABC". (3认同)
  • @RoyiNamir :虽然 BOM 可以“帮助”用户怀疑文件是 Unicode 而不是 ISO-8859-1,但您不能 100% 确定这一点。假设我向您发送了一个简单的文本文件,其中包含您的中文 (?) 字形的四个字节,告诉您它是 UTF-8。然后,您可以在不依赖 BOM 的情况下对其进行解码。在其他情况下,如果我向您发送一个 ISO-8859-1 文件,其中第一个字符是 BOM 的相同字节,那么您仍然必须将其解码为 ISO-8859-1。不是 UTF-8。只有当我给你发送一个文本文件而不告诉你它的编码时,BOM 的三个字节才会引导你。或者误导你。 (2认同)
  • @RoyiNamir - 在您给出的示例(http://i.imgur.com/7u1zLrS.png)中,仍然不需要UTF-8中的BOM,因为其字节顺序由标准定义.无论您使用的是小端还是大端系统,字符(U + 20B20)将始终只有一个有效的UTF-8编码,即四字节序列`F0 A0 AC A0`.这些字节的字节顺序由UTF-8标准严格定义,因此UTF-8中不需要任何字节顺序标记.(它用作编码标识符是一个不同的问题;我特别说不需要识别*字节顺序*.) (2认同)

J P*_*J P 125

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

  1. 不包含文本的文件不再为空,因为它们始终包含BOM.
  2. 保存UTF-8的ASCII子集内的文本的文件本身不再是ASCII,因为BOM不是ASCII,这使得一些现有工具崩溃,用户无法替换此类遗留工具.
  3. 无法将多个文件连接在一起,因为每个文件现在都有一个BOM.

并且,正如其他人所提到的那样,使用BOM来检测某些东西是UTF-8既不充分也不必要:

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

  • @ Cheersandhth.-Alf这个答案是对的.你只是指出微软的错误. (18认同)
  • 重点1"不保留文本的文件不再为空,因为它们始终包含BOM",这(1)将OS文件系统级别与解释的内容级别混淆,加上它(2)错误地假定使用BOM必须放置一个BOM也在每个其他空文件中.(1)的实际解决方案是不做(2).基本上,投诉减少为"可能不切实际地将BOM放入其他空文件中,从而阻止最容易检测逻辑空文件(通过检查文件大小)".仍然很好的软件应该能够处理它,因为它有一个目的. (8认同)
  • @brighty:虽然添加了一个bom,但情况没有改善. (8认同)
  • 重点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文件.一个可能更好的解决方案是放弃那些不合适的工具. (7认同)
  • 重点3,"不可能将几个文件连接在一起,因为每个文件现在都有一个BOM表",这是错误的.我没有问题将UTF-8文件与BOM连接,所以显然是可能的.我想也许你的意思是Unix-land`cat`不会给你*clean*结果,结果只在开始时有BOM.如果你的意思是,那就是因为`cat`在字节级工作,而不是在解释内容级别工作,并且以类似的方式`cat`不能处理照片,比方说.它仍然没有太大的伤害.这是因为BOM编码零宽度不间断空间. (7认同)
  • @ cheers-and-hth-alf我现在澄清了上述陈述; 它们是事实,没有涉及逻辑. (4认同)
  • 最后的声明,"正如其他人所提到的,使用BOM来检测某些东西是UTF-8既不充分也不必要." 是错的.在某些情况下,没有必要,但在其他情况下则是必要的.例如,Visual C++编译器在源代码文件的开头需要BOM,以便正确地将其编码标识为UTF-8. (2认同)
  • 总之,由于三点中的每一点加上最终陈述仍然是错误的和/或强烈误导,我支持我的downvote.我希望上面的解释是充分的.如果没有,那就问一下. (2认同)
  • BOM 的另一个问题...正则表达式无法将其识别为字符串的开头甚至行的开头 (2认同)
  • 陈述 1 和 3 是(部分)错误的。BOM 是 Unicode 字符“零宽度无间断空间”。仅包含 BOM 的文件不是空的,它包含一个正常(但不可见)的字符。在文本文件中,您可以根据需要放置任意数量的零宽度无间断空格字符。但是,[字节顺序标记 (BOM) 常见问题解答](https://www.unicode.org/faq/utf_bom.html#BOM) 说:*在文件中间 [...] U+FEFF 通常应该不会发生。为了向后兼容,它应该被视为零宽度非中断空间 (ZWNBSP),然后是文件或字符串内容的一部分。* (2认同)
  • @Cheersandhth.-Alf “保存 ASCII 文本的 UTF-8 文件不是 ASCII,而是 UTF-8 ... UTF-8 是 ASCII 的 8 位可变长度扩展。” 下定决心?如果 UTF-8 是 ASCII 的 8 位可变长度扩展,那么每个 MSB 为零的 UTF-8 文件就是 ASCII,否则它不会是 *扩展*。 (2认同)

rsp*_*rsp 73

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

所有答案都很一般.我想添加的是实际导致实际问题的BOM使用示例,但很多人不了解它.

BOM中断脚本

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

#!/bin/sh
#!/usr/bin/python
#!/usr/local/bin/perl
#!/usr/bin/env node
Run Code Online (Sandbox Code Playgroud)

它告诉系统在调用这样的脚本时需要运行哪个解释器.如果脚本以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
Run Code Online (Sandbox Code Playgroud)

现在,如果文件以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
Run Code Online (Sandbox Code Playgroud)

注意:

  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的输入,因为它不是以ASCII字符<128开头,因为它应该根据RFC.

其他数据格式

不需要JSON中的BOM,这是违法的,并且会破坏根据RFC正常工作的软件.它应该是一个没有使用它的nobrainer然而,总有人坚持使用BOM,注释,不同的引用规则或不同的数据类型来破坏JSON.当然,如果你需要的话,任何人都可以自由地使用BOM或其他东西 - 只是不要把它称为JSON.

对于除JSON之外的其他数据格式,请看看它的外观.如果唯一的编码是UTF-*且第一个字符必须是低于128的ASCII字符,那么您已经拥有了确定数据的编码和字节序所需的所有信息.即使作为可选功能添加BOM也只会使其更复杂且容易出错.

BOM的其他用途

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

  • @EricGrange,你似乎非常强烈地支持BOM,但没有意识到这将使所有无处不在的,普遍有用的,*最佳 - 最小*"纯文本"格式成为UTF8之前的遗留物!根据定义,将*任何类型的(带内)标头添加到*plain*文本流中会对最简单的文本文件强加一个强制协议*,使其永远不再是"最简单的"!为了什么收获?为了支持所有*其他*,古老的CP编码,*也*没有签名,所以你可能会把它们误认为是UTF-8?(顺便说一句,ASCII也是UTF-8.所以,那些也是那些BOM?)来吧.) (10认同)
  • 取代rfc4627的rfc7159实际上表明支持BOM可能不那么邪恶.基本上没有BOM只是一个模棱两可的kludge,因此旧的Windows和Unix软件不能识别Unicode仍然可以处理utf-8. (4认同)
  • @EricGrange - 真的吗?快速谷歌搜索表明与我相反:/sf/ask/203390771/ 是关于 UTF-8 BOM 如何显示为字符Eclipse(即 Eclipse 认为那里不应该有 BOM 并且不知道如何处理它),并且 https://dzone.com/articles/what-does-utf-8-bom-mean 说“在 Eclipse 中,如果我们将默认编码设置为 UTF-8,它将使用普通的 UTF-8,不带字节顺序标记 (BOM)”。是否有任何链接指向人们讨论“忽略”UTF-8 BOM 时 Eclipse 失败的地方? (4认同)
  • @EricGrange,如果你真的研究过,你的答案有点不诚实。您没有包含 rfc7159 的[链接](https://tools.ietf.org/html/rfc7159)。如果您这样做了,人们可能会读到:“实现不得在 JSON 文本的开头添加字节顺序标记。为了互操作性,解析 JSON 文本的实现可以忽略字节顺序标记的存在,而不是处理将其视为错误。” 这并不是“[表明]支持 BOM 可能没有那么邪恶”,而是表明明智的编码人员不会因为 Microsoft 创建的 UTF8-with-BOM 而使他们的程序崩溃。 (4认同)
  • 这个答案就是我提出这个问题的原因!我在 Windows 中创建 bash 脚本,并将这些脚本发布到 Linux 时遇到很多问题!杰森文件也是如此。 (3认同)
  • @EricGrange - 如果你决定追查工具链中的错误,我怀疑“gitblame”将在识别*谁*引入了带有乱码的提交方面非常有用,此时你可以向他们发送电子邮件并询问他们*他们经常使用什么工具*,并检查该工具的设置。它应该默认为 UTF-8,而不是“Latin-1”或不同的单字节代码页。任何工具都没有理由不默认先读取 UTF-8(即,在没有 BOM 的情况下),然后在文本文件无法正确解码为 UTF-8 时尝试其他代码页。希望这可以帮助! (3认同)
  • 听起来像JSON需要更新才能支持它,与Perl脚本,Python脚本,Ruby脚本和Node.js相同。仅仅因为这些平台选择不提供支持,并不一定会终止BOM的使用。苹果几年来一直试图杀死Adobe,而Adobe仍然存在。但是一个启发性的帖子。 (2认同)
  • 我希望我能对这个答案投大约五十次票。我还想补充一点,此时 UTF-8 已经赢得了标准之战,互联网上几乎所有生成的文本都是 UTF-8。一些最流行的编程语言(例如 C# 和 Java)在内部使用 UTF-16,但是当使用这些语言的程序员将文件写入输出流时,他们几乎总是将其编码为 UTF-8。因此,用BOM来标记UTF-8文件不再有意义;UTF-8应该是你阅读时使用的默认编码,只有在UTF-8解码失败时才尝试其他编码。 (2认同)

dan*_*n04 48

没有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,它可能是.

  • 这也会使有效的UTF-8无效,其中包含一个错误的字节,但是:/ (7认同)
  • -1"这会导致非BOM感知软件出现问题.",这对我来说从来都不是问题,但恰恰相反,没有BOM会导致BOM感知软件(特别是Visual C++)出现问题问题.所以这个陈述非常特定于平台**,这是一个狭隘的Unix-land观点,但是误导性地呈现,好像它适用于一般情况.它没有. (6认同)
  • 不,UTF-8没有BOM.这个答案是不正确的.请参阅Unicode标准. (5认同)
  • 仅查看字节时,您甚至可以认为您有一个纯 ASCII 文件。但这也可能是一个 utf-16 文件,您必须在其中查看单词而不是字节。现代软件应该了解 BOM。如果检测到无效序列、可以使用较小序列的代码点或作为代理的代码点,仍然读取 utf-8 可能会失败。对于 utf-16,当存在孤立代理时,读取也可能会失败。 (2认同)
  • @Alf,我不同意你将非 BOM 态度解释为“**特定于平台**,狭隘的 Unix 领域的观点”。对我来说,“Unix 土地”中思想狭隘的唯一原因是 MS 和 Visual C++ 出现在 *NIX 之前,但他们没有。MS(我猜是有意为之)开始在 UTF-8 而不是 UTF-16 中使用 BOM 的事实表明,他们提倡破坏 `sh`、`perl`、`g++` 和许多其他免费且强大的工具。想要事情顺利进行吗?只需**购买** MS 版本即可。MS 造成了特定于平台的问题,就像他们的 \x80-\x95 系列的灾难一样。 (2认同)

Hel*_*man 29

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

如果保存的CSV文件没有BOM,则Excel认为它是ANSI并显示乱码.一旦你在前面添加"EF BB BF"(例如,通过使用带有UTF-8的记事本重新保存它;或者使用带有BOM的UTF-8重新保存它),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)

  • 感谢这个优秀的提示,如果一个人正在创建供Excel使用的UTF-8文件.但在其他情况下,我仍会按照其他答案跳过BOM. (6认同)
  • *Excel认为它是ANSI并显示乱码*然后问题出在Excel中. (6认同)
  • 如果您创建仅包含ASCII的文件,以及稍后可能添加非ascii的文件,它也很有用.我刚遇到这样一个问题:期望utf8的软件,创建带有一些数据的文件供用户编辑.如果初始文件只包含ASCII,在某些编辑器中打开然后保存,则最终以latin-1结束,一切都会中断.如果我添加BOM,它将被编辑器检测为UTF8,一切正常. (5认同)
  • **在哪里阅读*推荐*以便将BOM用于该RFC?**最多,强烈建议在某些情况下不要禁止这样做. (4认同)

Hal*_*gür 17

在某个地方,某些地方,BOM往往会繁荣(没有双关语意图(sic)).当它蓬勃发展时(例如,浏览器,编辑器等无法识别),它会在文档开头显示为奇怪的字符(例如,HTML文件,JSON响应,RSS等)并导致像奥巴马在推特上谈论最近编码问题那样的尴尬.

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

  • @ user984003不,问题是微软误导了你.它所谓的UTF-8不是UTF-8.没有BOM的UTF-8就是UTF-8的真正含义. (12认同)
  • @JoelFan 我想不起来了,但我想尽管作者声称,双关语可能是有意为之:) (2认同)

Dav*_*dRR 16

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

以下是关于字节顺序标记(BOM)的维基百科文章的一些摘录,我相信这个问题可以为这个问题提供一个可靠的答案.

关于BOM和UTF-8的含义:

Unicode标准允许BOMUTF-8 ,但不要求或建议其使用.字节顺序在UTF-8中没有意义,因此它在UTF-8中的唯一用途是在开始时发信号通知文本流以UTF-8编码.

使用BOM的参数:

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

参数 FOR 使用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文档将添加BOM.

哪个更好, 没有 BOM:

IETF建议,如果一个协议或者(a)始终使用UTF-8,或(b)具有一些其它方式来指示正在使用什么编码,然后将其"应该禁止使用U + FEFF作为签名".

我的结论:

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

另请注意,虽然引用的维基百科文章表明许多Microsoft应用程序依赖于BOM来正确检测UTF-8,但并非所有 Microsoft应用程序都是如此.例如,正如指出的@barlop,使用带有UTF-8的Windows命令提示符时,命令等typemore不希望的BOM存在.如果BOM 本,它可以是有问题的,因为它是用于其他应用.


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

  • 我最好严格要求**没有BOM**.我发现`.htaccess`和`gzip压缩`结合UTF-8 BOM会产生编码错误更改为UTF-8编码而没有BOM遵循建议[如此处](http://stackoverflow.com/ a/27710011/4058484)解决问题 (3认同)

Rom*_*ain 7

没有BOM的UTF-8没有BOM,除了当文件的消费者需要知道(或将从知道中获益)该文件是否是UTF-8编码时,它没有比具有BOM的UTF-8更好.或不.

BOM通常用于确定编码的字节顺序,这在大多数用例中都不是必需的.

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

  • "这对UTF-8毫无用处,因为它仍然是每个字形8位." 呃...不,只有ASCII-7字形是UTF-8中的8位.除此之外的任何东西都将是16位,24位或32位. (2认同)
  • “ BOM通常可用于确定编码的字节序,这在大多数用例中不是必需的。” ...字节序根本不适用于UTF-8,而与用例无关。 (2认同)

pib*_*pib 7

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

"对于UTF-8既不要求也不建议使用BOM,但在从使用BOM的其他编码形式或将BOM用作UTF-8签名的UTF-8数据转换的上下文中可能会遇到"

  • 您是否有任何示例,其中软件根据之前编码的编码是否有 BOM 来决定是否使用带/不带 BOM 的 UTF-8?!这似乎是一个荒谬的主张 (2认同)

Jam*_*eld 7

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

编辑:只是想明确表示我更喜欢根本没有BOM,如果一些旧的垃圾破坏了它就添加它,并且替换旧的应用程序是不可行的.

不要期望UTF8的BOM.


Wer*_*eit 7

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


jpc*_*-ae 7

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

如上所述,UTF BOM(字节顺序标记)在确定字符串是否为UTF-8时的任何使用都是受过教育的猜测.如果有适当的元数据(如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上尤其如此,其中通常假定没有BOM的任何内容都使用遗留代码页.BOM告诉像Office这样的程序,是的,这个文件中的文本是Unicode; 这是使用的编码.

归结到它,我遇到的唯一问题是CSV.根据程序的不同,它必须或者必须没有BOM.例如,如果您在Windows上使用Excel 2007+,则必须使用BOM进行编码,如果您想要平滑打开它而不必使用导入数据.

  • 您的答案的最后一部分是 100% 正确的:使用 BOM 的“唯一”原因是当您必须与不使用 UTF-8 作为默认解析未知文件的有缺陷的软件进行互操作时。 (5认同)

小智 6

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

我在我的页面上使用多种语言(甚至是西里尔语)很长一段时间,当文件保存而没有BOM时,我重新打开它们以便使用编辑器进行编辑(如cherouvim所述),某些字符已损坏.

请注意,当您尝试使用UTF-8编码保存新创建的文件时,Windows的经典记事本会自动保存带有BOM的文件.

我个人使用没有BOM的BOM.html文件保存服务器端脚本文件(.asp,.ini,.aspx).

  • 感谢关于windows经典记事本的精彩提示.我已经花了一些时间找出完全相同的东西.我的结果是总是使用Notepad ++而不是windows classic Notepad.:-) (3认同)

Flo*_*ima 6

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

但是,当我们在Windows或Linux上拥有文本,CSV和XML文件时,情况并非如此.

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

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

<?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)

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

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

$file="\xEF\xBB\xBF".$string;
Run Code Online (Sandbox Code Playgroud)

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

  • 我知道这是一个陈旧的答案,但我只是想提一下这是错的.Linux上的文本文件(不能代替其他Unix)通常是/ UTF-8. (2认同)

Dav*_*vid 6

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

#!/bin/bash: No such file or directory
Run Code Online (Sandbox Code Playgroud)

响应shebang行指定您要使用的shell:

#!/bin/bash
Run Code Online (Sandbox Code Playgroud)

如果你保存为UTF-8,那么没有BOM(比如在BBEdit中)都会很好.

  • 那是因为微软已经改变了标准所说的含义.UTF-8没有BOM:他们创建了***Microsoft UTF-8***,它在数据流前面插入一个虚假的BOM,然后告诉你不,这实际上是UTF-8.它不是.它只是在扩展和腐败. (7认同)

Wer*_*eit 5

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

问:我应该如何处理 BOM?

答:以下是一些需要遵循的准则:

  1. 特定协议(例如 Microsoft 对 .txt 文件的约定)可能需要在某些 Unicode 数据流(例如文件)上使用 BOM。当您需要遵守此类协议时,请使用 BOM。

  2. 某些协议允许在未标记文本的情况下使用可选的 BOM。在这些情况下,

    • 在已知文本数据流是纯文本但编码未知的情况下,可以将 BOM 用作签名。如果没有 BOM,则编码可以是任何内容。

    • 如果已知文本数据流是纯 Unicode 文本(但不知道是哪种字节序),则可以将 BOM 用作签名。如果没有 BOM,则文本应解释为 big-endian。

  3. 一些面向字节的协议要求在文件开头使用 ASCII 字符。如果 UTF-8 与这些协议一起使用,则应避免使用 BOM 作为编码表单签名。

  4. 如果数据流的精确类型已知(例如 Unicode big-endian 或 Unicode little-endian),则不应使用 BOM。特别是,当数据流被声明为 UTF-16BE、UTF-16LE、UTF-32BE 或 UTF-32LE 时,不得使用 BOM。