关于unicode:UTF-8 和 UTF-8 无 BOM

What's the difference between UTF-8 and UTF-8 without BOM?

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


utf-8bom是文本流(ef bb bf)开始时的一个字节序列,它允许读者更可靠地猜测文件是用utf-8编码的。

通常情况下,BOM用于表示编码的结束地址,但是由于结束地址与UTF-8无关,因此BOM是不必要的。

根据Unicode标准,不建议使用UTF-8文件的物料清单:

2.6 Encoding Schemes

... Use of a BOM is neither required nor recommended for UTF-8, but may be
encountered in contexts where UTF-8 data is converted from other
encoding forms that use a BOM or where the BOM is used as a UTF-8
signature. See the"Byte Order Mark" subsection in Section 16.8,
Specials,
for more information.


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

  • 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字符串"????美国广播公司"
  • 合法的utf-8字符串"abc"

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

编码应该是已知的,而不是占卜的。


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

  • 不包含文本的文件不再为空,因为它们始终包含物料清单。
  • 在UTF-8的ASCII子集中保存文本的文件不再是ASCII文件,因为BOM不是ASCII,这使得一些现有的工具崩溃,用户可能无法替换这些遗留工具。
  • 无法将多个文件连接在一起,因为每个文件的开头都有一个BOM。
  • 而且,正如其他人所提到的,拥有一个BOM来检测某种东西是UTF-8,这既不充分也不必要:

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


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

    所有的答案都很笼统。我想补充的是,BOM使用的例子实际上会导致真正的问题,但很多人并不知道。

    物料清单中断脚本

    shell脚本、perl脚本、python脚本、ruby脚本、node.js脚本或任何其他需要由解释器运行的可执行文件-所有这些都以shebang行开始,看起来像是其中之一:

    1
    2
    3
    4
    #!/bin/sh
    #!/usr/bin/python
    #!/usr/local/bin/perl
    #!/usr/bin/env node

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

    参见维基百科,文章:shebang,章节:魔力数字:

    The shebang characters are represented by the same two bytes in
    extended ASCII encodings, including UTF-8, which is commonly used for
    scripts and other text files on current Unix-like systems. However,
    UTF-8 files may begin with the optional byte order mark (BOM); if the
    "exec" function specifically detects the bytes 0x23 and 0x21, then the
    presence of the BOM (0xEF 0xBB 0xBF) before the shebang will prevent
    the script interpreter from being executed. Some authorities recommend
    against using the byte order mark in POSIX (Unix-like) scripts,[14]
    for this reason and for wider interoperability and philosophical
    concerns. Additionally, a byte order mark is not necessary in UTF-8,
    as that encoding does not have endianness issues; it serves only to
    identify the encoding as UTF-8. [emphasis added]

    JSON中的BOM非法

    见RFC 7159第8.1节:

    Implementations MUST NOT add a byte order mark to the beginning of a JSON text.

    在JSON中,BOM是冗余的

    不仅在JSON中是非法的,还不需要确定字符编码,因为有更可靠的方法可以明确地确定在任何JSON流中使用的字符编码和结束地址(有关详细信息,请参见此答案)。

    BOM中断JSON解析器

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

    确定JSON的编码和结尾,检查nul字节的前4个字节:

    1
    2
    3
    4
    5
    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开头,它将如下所示:

    1
    2
    3
    4
    5
    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第一个字节后面没有3个nuls,因此无法识别
  • UTF-16BE在前4个字节中只有1个nul,因此无法识别。
  • UTF-16LE在前4个字节中只有1个nul,因此无法识别。
  • 根据实现的不同,所有这些可能被错误地解释为UTF-8,然后被错误地解释或拒绝为无效的UTF-8,或者根本无法识别。

    另外,如果实现按照我的建议测试有效的JSON,它甚至会拒绝实际上编码为UTF-8的输入,因为它不会以ASCII字符<128开头,因为它应该按照RFC进行。

    其他数据格式

    JSON中的BOM不需要,是非法的,并且破坏了根据RFC正确工作的软件。当时不使用它应该是一种高尚的做法,但是,总是有人坚持使用bom、注释、不同的引用规则或不同的数据类型来破坏JSON。当然,如果你需要的话,任何人都可以自由使用boms或者其他任何东西——那就不要叫它json。

    对于JSON以外的其他数据格式,请看一下它的实际外观。如果唯一的编码是utf-*并且第一个字符必须是小于128的ASCII字符,那么您已经拥有了确定数据的编码和结束地址所需的所有信息。即使将bom作为可选功能添加,也只会使其更加复杂和容易出错。

    物料清单的其他用途

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


    What's different between UTF-8 and UTF-8 without BOM?

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

    长回答:

    最初,预期unicode将以utf-16/ucs-2编码。物料清单是为此编码表单设计的。当您有两个字节的代码单元时,需要指明这两个字节的顺序,这样做的一个常见约定是在数据的开头将字符u+feff作为"字节顺序标记"。字符u+fffe是永久未分配的,因此它的存在可以用来检测错误的字节顺序。

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

    Which is better?

    没有。正如MartinCote所回答的,Unicode标准不推荐使用它。它会导致不了解BOM的软件出现问题。

    检测文件是否为UTF-8的更好方法是执行有效性检查。UTF-8对哪些字节序列是有效的有严格的规则,所以假阳性的概率可以忽略不计。如果一个字节序列看起来像UTF-8,那么它很可能是。


    带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)


    bom倾向于在某个地方或某个地方蓬勃发展(没有双关语(sic))。当它繁荣时(例如,浏览器、编辑等无法识别),它会在文档开始时显示为奇怪的字符???(例如,HTML文件、JSON响应、RSS等),并导致类似最近奥巴马在Twitter上所说的编码问题这样的尴尬。

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


    Question: What's different between UTF-8 and UTF-8 without a BOM? Which is better?

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

    关于BOM和UTF-8的含义:

    The Unicode Standard permits the BOM in UTF-8, but does not require
    or recommend its use. Byte order has no meaning in UTF-8, so its
    only use in UTF-8 is to signal at the start that the text stream is
    encoded in UTF-8.

    不使用物料清单的参数:

    The primary motivation for not using a BOM is backwards-compatibility
    with software that is not Unicode-aware... Another motivation for not
    using a BOM is to encourage UTF-8 as the"default" encoding.

    使用物料清单的参数:

    The argument for using a BOM is that without it, heuristic analysis is
    required to determine what character encoding a file is using.
    Historically such analysis, to distinguish various 8-bit encodings, is
    complicated, error-prone, and sometimes slow. A number of libraries
    are available to ease the task, such as Mozilla Universal Charset
    Detector and International Components for Unicode.

    Programmers mistakenly assume that detection of UTF-8 is equally
    difficult (it is not because of the vast majority of byte sequences
    are invalid UTF-8, while the encodings these libraries are trying to
    distinguish allow all possible byte sequences). Therefore not all
    Unicode-aware programs perform such an analysis and instead rely on
    the BOM.

    In particular, Microsoft compilers and interpreters, and many
    pieces of software on Microsoft Windows such as Notepad will not
    correctly read UTF-8 text unless it has only ASCII characters or it
    starts with the BOM, and will add a BOM to the start when saving text
    as UTF-8. Google Docs will add a BOM when a Microsoft Word document is
    downloaded as a plain text file.

    有或没有物料清单,哪一个更好:

    The IETF recommends that if a protocol either (a) always uses UTF-8,
    or (b) has some other way to indicate what encoding is being used,
    then it"SHOULD forbid use of U+FEFF as a signature."

    我的结论是:

    只有在与软件应用程序的兼容性是绝对必要的情况下才使用BOM。

    另外请注意,尽管引用的维基百科文章指出,许多Microsoft应用程序依赖于BOM来正确检测UTF-8,但并非所有Microsoft应用程序都是如此。例如,@barlop指出,当使用带有utf-8&dagger;的windows命令提示符时,typemore等命令不希望出现BOM。如果存在物料清单,它可能会像其他应用程序一样有问题。

    &dagger;chcp命令通过代码页65001支持UTF-8(不含BOM)。


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

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

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

    我个人保存服务器端脚本文件(.asp,.ini,.aspx)与bom和.html文件没有bom。


    在bom上的维基百科页面底部引用:http://en.wikipedia.org/wiki/byte-order_mark_cite_note-2

    "Use of a BOM is neither required nor recommended for UTF-8, but may be encountered in contexts where UTF-8 data is converted from other encoding forms that use a BOM or where the BOM is used as a UTF-8 signature"


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

    编辑:我只想澄清一下,我更喜欢完全没有这个BOM,如果一些旧的垃圾把它弄坏了,就把它添加进去,替换旧的应用程序是不可行的。

    不要做任何事情,除了UTF8的BOM。


    没有bom的utf-8没有bom,这并没有比带有bom的utf-8更好,除非文件的使用者需要知道(或者从中受益)文件是否是utf-8编码的。

    BOM通常有助于确定编码的结束语,这在大多数用例中是不需要的。

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


    应该注意的是,对于某些文件,即使在Windows上也不能有BOM。例如SQL*plusVBScript文件。如果这样的文件包含一个物料清单,那么当您试图执行它们时就会出错。


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

    但当我们在Windows或Linux上拥有文本、csv和xml文件时,情况并非如此。

    例如,Windows或Linux中的文本文件是最容易想到的事情之一,它不是(通常)UTF-8。

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

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

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

    我有一系列包含法语字母的数据,这些数据需要保存为XML进行联合。不需要从头创建UTF-8文件(更改IDE和"创建新文件"中的选项),也不需要在文件开头添加BOM

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

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


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

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

    响应shebang行,指定要使用的外壳:

    1
    #!/bin/bash

    如果您保存为utf-8,那么没有bom(比如bbedit)都会很好。


    这个问题已经有一百万个答案,其中许多答案都很好,但我想试着澄清什么时候应该或不应该使用BOM。

    如前所述,在确定字符串是否为UTF-8时使用UTF BOM(字节顺序标记)是一种有根据的猜测。如果有合适的元数据可用(如charset="utf-8"),那么您就已经知道应该使用什么了,否则您需要进行测试并做出一些假设。这涉及到检查字符串来自的文件是否以十六进制字节代码ef bb bf开头。

    如果找到了与utf-8bom对应的字节代码,那么这个概率就足够高,可以假设它是utf-8,您可以从那里开始。然而,当被迫做出这种猜测时,在阅读时进行额外的错误检查仍然是一个好主意,以防出现混乱。如果输入的源代码绝对不应该是UTF-8,那么您应该只假设一个BOM不是UTF-8(即拉丁语-1或ANSI)。但是,如果没有BOM,您可以通过对编码进行验证来简单地确定它是否应该是UTF-8。

    为什么不推荐物料清单?

  • 不支持Unicode或不兼容的软件可能会假定它是拉丁语1或ANSI,并且不会从字符串中去掉BOM,这显然会导致问题。
  • 这不是真正需要的(只需检查内容是否兼容,并在找不到兼容编码时始终使用UTF-8作为回退)
  • 什么时候用物料清单编码?

    如果您不能以任何其他方式记录元数据(通过charset标记或文件系统meta),以及像boms一样使用的程序,则应该使用bom进行编码。这在Windows上尤其如此,在Windows中,没有BOM的任何东西通常都被认为是在使用遗留代码页。BOM告诉像Office这样的程序,是的,这个文件中的文本是Unicode;下面是使用的编码。

    归根结底,我唯一真正有问题的文件是csv。根据程序的不同,它要么必须,要么不能有一个BOM。例如,如果您在Windows上使用Excel2007+,那么如果您想顺利打开它,而不必借助于导入数据,那么必须使用BOM对其进行编码。


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

    保存时布局总是会被破坏。我花了些时间才解决这个问题。这些文件在Firefox中很好地工作,但是在Internet Explorer中又显示了一个CSS的怪癖,破坏了布局。在处理链接的CSS文件数小时后,我发现Internet Explorer不喜欢bomfed HTML文件。再也不要了。

    另外,我在维基百科上发现了这个:

    The shebang characters are represented by the same two bytes in extended ASCII encodings, including UTF-8, which is commonly used for scripts and other text files on current Unix-like systems. However, UTF-8 files may begin with the optional byte order mark (BOM); if the"exec" function specifically detects the bytes 0x23 0x21, then the presence of the BOM (0xEF 0xBB 0xBF) before the shebang will prevent the script interpreter from being executed. Some authorities recommend against using the byte order mark in POSIX (Unix-like) scripts,[15] for this reason and for wider interoperability and philosophical concerns


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

    Q: How I should deal with BOMs?

    A: Here are some guidelines to follow:

  • A particular protocol (e.g. Microsoft conventions for .txt files) may require use of the BOM on certain Unicode data streams, such as
    files. When you need to conform to such a protocol, use a BOM.

  • Some protocols allow optional BOMs in the case of untagged text. In those cases,

    • Where a text data stream is known to be plain text, but of unknown encoding, BOM can be used as a signature. If there is no BOM,
      the encoding could be anything.

    • Where a text data stream is known to be plain Unicode text (but not which endian), then BOM can be used as a signature. If there
      is no BOM, the text should be interpreted as big-endian.

  • Some byte oriented protocols expect ASCII characters at the beginning of a file. If UTF-8 is used with these protocols, use of the
    BOM as encoding form signature should be avoided.

  • Where the precise type of the data stream is known (e.g. Unicode big-endian or Unicode little-endian), the BOM should not be used. In
    particular, whenever a data stream is declared to be UTF-16BE,
    UTF-16LE, UTF-32BE or UTF-32LE a BOM must not be used.


  • 来自http://en.wikipedia.org/wiki/byte-order_mark:

    The byte order mark (BOM) is a Unicode
    character used to signal the
    endianness (byte order) of a text file
    or stream. Its code point is U+FEFF.
    BOM use is optional, and, if used,
    should appear at the start of the text
    stream. Beyond its specific use as a
    byte-order indicator, the BOM
    character may also indicate which of
    the several Unicode representations
    the text is encoded in.

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

    我对缺少BOM的真正问题是。假设我们有一个文件,其中包含:

    1
    abc

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

    1
    abg-αβγ

    哎呀。。。现在文件仍在ANSI中,猜猜看,"αβγ"不占6个字节,而是3个字节。这不是UTF-8,这会在以后的开发链中引起其他问题。


    如果在HTML文件中使用UTF-8,或者在同一页中使用塞尔维亚西里尔文、塞尔维亚拉丁语、德语、匈牙利语或其他外来语言,则带BOM的UTF更好。这是我的观点(计算机和IT行业30年)。