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

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

UTF-8 BOM是一个字节序列(EF BB BF),允许读者将文件标识为以UTF-8编码。

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

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

2.6编码scheme

…对于UTF-8既不要求也不build议使用BOM,但是在UTF-8数据从使用BOM的其他编码forms转换或使用BOM作为UTF-8签名的上下文中可能遇到。 有关更多信息请参见第16.8节 “特殊内容”中的“字节顺序标记”小节。

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

  • UTF-8和BOM-UTF-8之间没有正式的区别
  • BOM-UTF-8string将以下面三个字节开头。 EF BB BF
  • 这些字节(如果存在)在从文件/stream中提取string时必须被忽略。

但是,作为附加信息,对于UTF-8的BOM来说,如果string是以UTF-8编码的话,它可能是一种很好的方法,或者它可能是任何其他编码中的合法string。

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

  • 合法的ISO-8859-1string“ABC”
  • 合法的UTF-8string“ABC”

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

编码应该是已知的,不是必须的。

把BOM放在UTF-8编码文件中至less有三个问题。

  1. 不包含文本的文件不再为空,因为它们始终包含BOM。
  2. 保存在UTF-8的ASCII子集中的文本的文件不再是它们自己的ASCII,因为BOM不是ASCII,这使得一些现有的工具崩溃了,并且用户可能无法replace这些传统工具。
  3. 将几个文件连接在一起是不可能的,因为每个文件现在都有一个BOM。

而且,正如其他人所提到的那样,用BOM来检测UTF-8是不够的也是不必要的:

  • 这是不够的,因为任意字节序列可能以构成BOM的确切序列开始。
  • 这是没有必要的,因为你可以只读字节,就好像它们是UTF-8; 如果成功的话,按照定义,它是有效的UTF-8。

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

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

很长的回答:

最初预计Unicode将以UTF-16 / UCS-2编码。 BOM是为这种编码formsdevise的。 当你有2字节的代码单元时,有必要指出这两个字节在哪一个顺序中,这样做的通用约定是在数据的开始部分包含字符U + FEFF作为“字节顺序标记”。 字符U + FFFE是永久未分配的,所以它的存在可以用来检测错误的字节顺序。

UTF-8具有相同的字节顺序,而不pipe平台字节顺序如何,所以不需要字节顺序标记。 但是,在从UTF-16转换为UTF-8的数据中,或者作为表示数据为UTF-8的“签名”,可能会出现(如字节序列EF BB FF )。

哪个更好?

没有。 正如Martin Cote所回答的那样,Unicode标准并不推荐它。 这会导致无BOM感知软件的问题。

检测文件是否为UTF-8的更好方法是执行有效性检查。 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编码的,那么可以试着在开始时join一个BOM表。 但实际上“#!” 字符不只是字符。 它们实际上是一个幻数 ,碰巧是由两个ASCII字符组成的。 如果你在这些字符之前放置了一些东西(比如BOM),那么这个文件看起来就像是一个不同的幻数,并且会导致问题。

参见维基百科, 文章:Shebang,部分:幻数 :

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

BOM在JSON中是非法的

请参阅RFC 7159,第8.1节 :

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

BOM在JSON中是冗余的

不仅在JSON中是非法的, 也不需要确定字符编码,因为有更可靠的方法可以明确地确定任何JSONstream中使用的字符编码和字节顺序(请参阅此答案的详细信息)。

BOM打破了JSONparsing器

这不仅在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,或根本不被识别。

此外,如果按照我的build议testing有效的JSON,它甚至会拒绝那些真正编码为UTF-8的input,因为它不是以ASCII字符<128开始的,因为它应该根据RFC。

其他数据格式

JSON中的BOM是不需要的,是违法的,根据RFC打破正常工作的软件。 如果不使用它,那应该是一个难题,但总是有人坚持使用BOM,注释,不同的引用规则或不同的数据types来打破JSON。 当然,如果你需要的话,任何人都可以自由使用物料清单或其他任何东西 – 只是不要把它叫做JSON。

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

BOM的其他用途

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

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

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

RFC 3629build议在“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的谈话中经历 。

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

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

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

关于BOM和UTF-8的含义:

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

使用BOM的 参数

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

使用BOM的 参数

使用BOM的参数是,如果没有它,启发式分析是必需的,以确定什么字符编码文件正在使用。 历史上这样的分析,为了区分各种8位编码,是复杂的,容易出错的,有时很慢。 许多库可以用来简化任务,例如Mozilla Universal Charset Detector和Unicode的国际组件。

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

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

哪个更好, 没有 BOM:

IETFbuild议,如果一个协议要么(a)总是使用UTF-8,要么(b)有其他的方式来指明正在使用什么编码,那么它“应该禁止使用U + FEFF作为签名”。

我的结论:

当与Microsoft软件或其他软件的兼容性绝对必要时才使用BOM。

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

“对于UTF-8既不要求也不build议使用BOM,但是在UTF-8数据从使用BOM的其他编码forms或将BOM用作UTF-8签名转换的上下文中,

我从另一个angular度来看待这个问题。 我认为带有BOM的UTF-8更好,因为它提供了关于文件的更多信息。 我只有在遇到问题时才使用没有BOM的UTF-8。

我在我的页面上使用多种语言(甚至西里尔语 )很长一段时间,当文件保存没有BOM,我重新打开它们用编辑器编辑(如cherouvim也注意到),一些字符已损坏。

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

我亲自保存带BOM.html文件的服务器端脚本文件(.asp,.ini,.aspx), 无需BOM

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

BOM通常用于确定编码的字节顺序,这在大多数用例中并不需要。

另外,对于不了解或关心的消费者而言,BOM可能是不必要的噪音/痛苦,并且可能导致用户混淆。

当你想显示以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。 如果不从一开始就创build一个UTF-8文件(在IDE和“创build新文件”中更改选项),或者在文件的开头添加BOM

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

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

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

编辑:只是想明确表示,我宁愿没有BOM,如果一些旧的垃圾违反了它,添加它,并取代遗留的应用程序是不可行的。

对于UTF8,不要做任何期望的BOM。

应该注意,对于某些文件,即使在Windows上也不能有BOM。 例子是SQL*plusVBScript文件。 如果这些文件包含物料清单,则在尝试执行时会出现错误。

这个问题已经有了百万分之一的答案,其中很多都是相当不错的,但是我想试着澄清一下什么时候应该或不应该使用BOM。

如前所述,任何使用UTF BOM(字节顺序标记)来判断一个string是否为UTF-8都是有教育意义的猜测。 如果有适当的元数据可用(如charset="utf-8" ),那么你已经知道你应该使用什么,但否则你需要testing和做一些假设。 这包括检查一个string是否来自文件的开头是hex字节代码EF BB BF。

如果find与UTF-8 BOM相对应的字节码,则该概率足够高,可以假设它是UTF-8,并且可以从那里开始。 当被迫做这个猜测时,然而,在阅读时进行额外的错误检查仍然是一个好主意,以防出现乱码。 如果input绝对不是基于UTF-8的源,则应该只假定BOM不是UTF-8(即,latin-1或ANSI)。 但是,如果没有BOM,可以通过validation编码来简单地确定它是否应该是UTF-8。

为什么不推荐BOM?

  1. 非Unicode感知或不合规的软件可能会认为它是latin-1或ANSI,并且不会从string中去除BOM,这显然会导致问题。
  2. 这不是真的需要(只要检查内容是否符合规范,并且在没有符合规范的编码时总是使用UTF-8作为后备)

什么时候应该用BOM编码?

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

当涉及到它,唯一的文件我真的有问题是CSV。 根据程序的不同,它必须或者不能有BOM。 例如,如果您在Windows上使用Excel 2007+,则必须使用BOM进行编码,才能顺利打开,而不必诉诸于导入数据。

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

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

作为对shebang行的回应,指定您希望使用哪个shell:

 #!/bin/bash 

如果你保存为UTF-8,没有BOM(比如在BBEdit中 )一切都会好的。

http://en.wikipedia.org/wiki/Byte-order_mark

字节顺序标记(BOM)是用于表示文本文件或stream的字节顺序(字节顺序)的Unicode字符。 其代码点是U + FEFF。 材料清单的使用是可选的,如果使用,应该出现在文本stream的开始。 除了作为字节顺序指示符的具体使用之外,BOM字符还可以指示文本被编码在几个Unicode表示中的哪一个。

始终在您的文件中使用BOM将确保它始终在支持UTF-8和BOM的编辑器中正确打开。

我没有BOM的真正问题如下。 假设我们有一个文件,其中包含:

 abc 

如果没有BOM,在大多数编辑器中将以ANSI打开。 所以这个文件的另一个用户打开它并附加一些本地字符,例如:

 abg-αβγ 

糟糕…现在文件还在ANSI中,猜测“αβγ”不占用6个字节,但是3.这不是UTF-8,这会在开发链中产生其他问题。

如上所述,带有BOM的UTF-8可能会导致无BOM(或兼容)软件的问题。 我曾经用基于Mozilla的KompoZer编辑过编码为UTF-8 + BOM的HTML文件,因为客户需要这个所见即所得的程序。

保存时,布局总是会被破坏。 我花了一些时间来摆弄这个。 这些文件然后在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)将阻止脚本解释器被执行。 有些权威人士build议不要在POSIX(Unix-like)脚本中使用字节顺序标记[15],因为这个原因和更广泛的互操作性和哲学问题

如果您在HTML文件中使用UTF-8,如果在同一页面中使用塞尔维亚西里尔文,塞尔维亚拉丁文,德文,匈牙利语或其他奇特的语言,那么使用BOM的UTF更好。 这是我的看法(30年的计算机和IT行业)。