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

时间:2010-02-08 18:26:21

标签: unicode utf-8 character-encoding byte-order-mark

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

21 个答案:

答案 0 :(得分:689)

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

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

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

  

2.6编码方案

     

......对于UTF-8既不要求也不建议使用BOM,但可能是   在从其他地方转换UTF-8数据的上下文中遇到的   编码使用BOM的表单或将BOM用作UTF-8的表单   签名。请参阅Section 16.8, Specials中的“字节顺序标记”小节,   了解更多信息。

答案 1 :(得分:209)

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

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

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

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

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

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

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

答案 2 :(得分:114)

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

  1. 不包含文字的文件不再为空,因为它们始终包含BOM。
  2. 包含UTF-8的ASCII子集内的文本的文件不再是ASCII,因为BOM不是ASCII,这使得一些现有工具失效,用户无法替换此类传统工具。
  3. 无法将多个文件连接在一起,因为每个文件现在都有一个BOM。
  4. 并且,正如其他人所提到的那样,使用BOM来检测某些东西是UTF-8既不充分也不必要:

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

答案 3 :(得分:66)

这是一个很老的问题,有许多好的答案,但有一点需要补充。

所有答案都很一般。我想添加的是实际导致实际问题的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。但实际上是“#!”字符不仅仅是字符。它们实际上是magic number,恰好由两个ASCII字符组成。如果您在这些字符之前放置了某些内容(如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中非法而且不需要,它实际上打破了使用{中提供的方法确定编码的所有软件 {3}}:

确定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,因此无法识别
  5. 根据实施情况,所有这些都可能被错误地解释为UTF-8,然后被误解或拒绝为无效的UTF-8,或根本无法识别。

    此外,如果实现测试我推荐的有效JSON,它甚至会拒绝确实编码为UTF-8的输入,因为它不是以ASCII字符<根据RFC,它应该是128。

    其他数据格式

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

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

    BOM的其他用途

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

答案 4 :(得分: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,则可能是。

答案 5 :(得分: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

答案 6 :(得分:17)

在某个地方,某些地方,BOM往往会繁荣(没有双关语意图(原文如此))。当它激增时(例如,浏览器,编辑器等无法识别),它会在文档的开头显示为奇怪的字符(例如,HTML文件,{{3 }}响应,JSON等等,并导致像RSS这样的尴尬。

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

答案 7 :(得分:16)

  

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

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

关于BOM和UTF-8的含义:

  

Unicode标准允许 UTF-8 中的 BOM ,但不需要   或推荐使用它。字节顺序在UTF-8中没有意义,所以它的   仅在UTF-8中使用的是在文本流的开头发出信号   以UTF-8编码。

使用BOM NOT 的论据

  

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

参数 FOR 使用BOM:

  

使用BOM的论据是没有它,启发式分析就是   需要确定文件使用的编码字符。   历史上这种分析,以区分各种8位编码,是   复杂,容易出错,有时甚至很慢。一些图书馆   可以轻松完成任务,例如Mozilla Universal Charset   用于Unicode的检测器和国际组件。

     

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

     

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

哪个更好, WITH 没有 < / strong> 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)的支持。

答案 8 :(得分:7)

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

  

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

答案 9 :(得分:7)

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

答案 10 :(得分:7)

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

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

不要为UTF8做任何预期的BOM。

答案 11 :(得分:6)

如果要显示以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文件中。

答案 12 :(得分:6)

这个问题已经有一百万个答案了,其中很多都很好,但我想尝试澄清何时应该或不应该使用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作为后备)
  3. 时,您使用BOM进行编码?

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

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

答案 13 :(得分:6)

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

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

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

#!/bin/bash

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

答案 14 :(得分:6)

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

我在我的网页上使用多种语言(甚至是Cyrillic)很长一段时间,当文件保存而没有BOM时我会重新打开它们以便使用编辑器进行编辑(如cherouvim也是注意到),某些角色已损坏。

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

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

答案 15 :(得分:6)

没有物料清单的UTF-8没有物料清单,这不会比带有物料清单的UTF-8更好,除非文件的消费者需要知道(或将从中获益)文件是否是UTF- 8编码与否。

BOM通常可用于确定编码的字节顺序,大多数用例都不需要这样做。

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

答案 16 :(得分:4)

如上所述,带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],因为这个原因以及更广泛的互操作性和哲学问题

答案 17 :(得分:4)

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

  问:我应该如何处理物料清单?

     

答:以下是一些指导原则:

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

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

         
        
    • 如果已知文本数据流是纯文本,但编码未知,则BOM可用作签名。如果没有BOM,   编码可以是任何东西。

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

    •   
  4.   
  5. 某些面向字节的协议需要文件开头的ASCII字符。如果UTF-8与这些协议一起使用,请使用   应避免使用BOM作为编码形式签名。

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

  8.   

答案 18 :(得分:1)

来自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,这会在以后的开发链中引起其他问题。

答案 19 :(得分:0)

这是我对Visual Studio,SourceTree和Bitbucket拉取请求的经验,这给了我一些问题:

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

enter image description here

如果将鼠标悬停在它上面,它将显示一个类似于“ ufeff”的字符,但结果表明sourcetree没有显示这些类型的字节标记,因此它很可能最终出现在您的请求请求中,这应该没问题,因为那样VS 2017现在对新文件进行编码,因此bitbucket可能会忽略此文件或使其以其他方式显示,请参见此处的更多信息:

Red dot marker BitBucket diff view

答案 20 :(得分:-4)

如果您在HTML文件中使用UTF-8,如果您在同一页面中使用塞尔维亚语西里尔语,塞尔维亚语,德语,匈牙利语或某种外来语言,那么带有BOM的UTF会更好。这是我的观点(30年的计算和IT行业)。