字节顺序记号

本页使用了标题或全文手工转换,现处于中国大陆简体模式
求闻百科,共笔求闻

比特组顺序标记(英语:byte-order markBOM)是位于码点U+FEFF统一码字符的名称。当以UTF-16UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其比特组序。它常被用来当做标示文件是以UTF-8UTF-16UTF-32编码的标记。

比特组顺序标记通常有几种涵义[1]

  1. 在16位和32位的情况下,文字流的比特组顺序
  2. 表示文字流非常有可能是Unicode编码。
  3. 使用的是哪一种Unicode字符编码

比特组顺序标记的使用是选择性的。它的存在会干扰那些不希望文件开头出现非ASCII字符、但可以用其他方式处理文字流的软件对于UTF-8的使用。

Unicode可以以8位、16位或32位整数为单位进行编码。对于16位和32位的表示方法,从任意来源接收文本的电脑需要知道整数是以何种比特组顺序编码的。比特组顺序标记的编码方式与文件文件的其他部分相同,如果它的比特组被调换,就会变成一个非字符的Unicode码位。因此,访问文本的过程中,可以透过检查这头几个比特组来确定比特组顺序,而不需要文字流本身以外的一些约定或元资料。一般来说,如果有必要,接收资料的电脑会将比特组换成自己的比特组顺序,不再需要比特组顺序标记进行处理。

每个Unicode编码(包括Unicode标准以外的编码,如UTF-7,见下表)的BOM比特组序列都不一样,而且这些序列都不可能出现在以其他编码储存的文字流的开头。因此,在文字流的开头放置一个编码的BOM,可以表明文本是Unicode,并识别所使用的编码方案。这种对BOM字符的使用被称为“Unicode签名”[2]

使用

字符U+FEFF如果出现在字节流的开头,则用来标识该字节流的字节序,是高位在前还是低位在前。如果它出现在字节流的中间,则表达零宽度非换行空格的意义,用户看起来就是一个空格。从Unicode3.2开始,U+FEFF只能出现在字节流的开头,只能用于标识字节序,就如它的名称——字节顺序标记——所表示的一样;除此以外的用法已被舍弃。取而代之的是,使用U+2060来表达零宽度无断空白。

UTF-8

UTF-8中,虽然在 Unicode 标准上允许比特组顺序标记的存在[3],但实际上并不一定需要[4]。UTF-8编码过的比特组顺序标记则被用来标示它是UTF-8的文件。它只用来标示一个UTF-8的文件,而不用来说明比特组顺序[5]。但同时,该标准也不建议在有比特组顺序标记的情况下将其删除,以便在不同的编码之间转换时不会丢失资讯,并让依赖比特组顺序标记的程序能顺利运作[6][7]。IETF建议,如果一个协议(a)总是使用UTF-8,或者(b)有一些其他方法来表明正在使用的编码,那么它“应该禁止使用U+FEFF作为签名”[8]。 许多视窗程序(包含记事本)会需要添加比特组顺序标记到UTF-8文件,否则将无法正确解析编码,而出现乱码。然而,在类Unix系统(大量使用文本文件,用于文件格式,用于行程间通讯)中,这种做法则不被建议采用。因为它会妨碍到如解译器脚本开头的Shebang等的一些重要的码的正确处理。它亦会影响到无法识别它的编程语言。如gcc会报告源码档开头有无法识别的字符。而在PHP中,如果没有启用输出缓冲(output buffering),它会使得页面内容开始被送往浏览器(即:用户标头档已被提交),这使PHP脚本无法指定用户标头档(HTTP Header)。比特组顺序标记在UTF-8中被表示为序列0xEF 0xBB 0xBF,对大部分未准备好处理UTF-8的文本编辑器网页浏览器而言,在ISO-8859-1的环境中则会显示

Unicode标准允许在UTF-8中使用BOM,但并不要求或推荐使用它。比特组顺序在UTF-8中没有任何意义,所以它在UTF-8中的唯一用途是在开始时发出信号,表明文本流是用UTF-8编码的,或者表明它是从包含可选BOM的文本流转换到UTF-8的。该标准也不建议在有BOM的情况下将其删除,以便在不同的编码之间往返不会丢失信息,并使依赖BOM的代码继续工作。 IETF建议,如果一个协议要么(a)总是使用UTF-8,要么(b)有一些其他方法来表明正在使用的编码,那么它 "应该禁止使用U+FEFF作为签名"。

UTF-8是一种稀疏的编码,意思是很大一部分可能的字符组合不会产生有效的UTF-8文本。任何其他编码的二进制资料和文本都可能包含UTF-8无效的字符序列,唯一的例外是当文本纯粹由ASCII范围的字符组成的时候。因为所有的现代编码都使用ASCII范围的比特组来表示ASCII字符,所以无论发出这些比特组的系统打算使用什么编码,纯ASCII的文本都可以被安全地解释为UTF-8。由于这些考虑,使用启发式的分析方法可以很有把握地检测出文件是否使用UTF-8,而不需要加入BOM。 另一方面,微软的编译器[9]和解释器,以及许多Microsoft Windows上的软件,如记事本,都将BOM视为一个必要的神奇数字,而不是使用启发式分析法。这些工具在将文本保存为UTF-8时添加了BOM,并且只有在BOM存在或是文件只包含ASCII字符时才能解释UTF-8。Windows PowerShell(截至5.1版本)在保存UTF-8的XML文件档时,会添加一个BOM。然而,PowerShell Core 6在一些cmdlets上增加了一个-Encoding开关,称为“utf8NoBOM”,这样就可以在没有BOM的情况下保存文件档。Google文档在将文件档转换为纯文本文件以供下载时也会添加BOM。

UTF-16

UTF-16中,比特组顺序标记被放置为文件或文字符串流的第一个字符,以标示在此文件或文字符串流中,以所有十六比特为单位的字码的端序(比特组顺序)。如果试图用错误的比特组顺序来读取这个流,比特组将被调换,从而产生字符U+FFFE,这个字符被Unicode定义为“非字符”,不应该出现在文本中。例如,值为U+FFFE的码位被保证将不会被指定成一个统一码字符。这意味着0xFF0xFE将只能被解释成小端序中的U+FEFF(因为不可能是大端序中的U+FFFE)。

  • 如果十六比特单位被表示成大端序,这比特组顺序标记字符在序列中将呈现0xFE,其后跟着0xFF(其中的0x用来标示十六进位)。
  • 如果十六比特单位使用小端序,这个比特组序列为0xFF,其后接着0xFE

这两个序列都不是有效的UTF-8,所以它们的出现表明该文件不是用UTF-8编码的。

对于网际网路号码分配局注册的字符集UTF-16BE和UTF-16LE,不应该使用比特组顺序标记标记,因为这些字符集的名称已经决定了比特组顺序。如果在这样的文本流中的任何地方遇到U+FEFF,将被解释为一个“零宽度无断点空间”。

如果没有比特组顺序标记,可以透过搜索ASCII字符(即与0x20-0x7E范围内的字节相邻的0比特组,还有CR和LF的0x0A和0x0D)来猜测该文本是否为UTF-16及其比特组顺序。大量的(即远远高于随机)相同的顺序是UTF-16的一个非常好的指示,而0是在偶数还是奇数比特组中表明了比特组的顺序。然而,这依然可能会导致假阳性和假阴性。

Unicode标准的一致性条款D98(第3.10节)规定:“UTF-16编码方案可以以BOM开始,也可以不以BOM开始。然而,当没有BOM时,在没有高层协议的情况下,UTF-16编码方案的比特组顺序是大端序。”是否有更高层次的协议是可以解释的。例如,在一台本地比特组顺序为小端序的电脑上的文件,可能被默认为是以UTF-16LE编码。因此,大端序的推定被广泛地忽略了。在HTML5中使用的W3C/WHATWG编码标准规定,标记为“utf-16”或“utf-16le”的内容将被解释为小端序,“以处理部署的内容”[10]。然而,如果出现了比特组顺序标记,那么该标记将被视为“比其他任何东西都更有权威性”[11]

将UTF-16解释为基于比特组的编码的程序可能会显示出乱七八糟的字符,但是ASCII字符会被识别出来,因为UTF-16表示的低字符与ASCII代码相同,因此会显示相同的字符。0的上字符可以显示为无、空白、句号,或其他一些不变的字形。

UTF-32

虽然比特组顺序标记亦可以用于UTF-32,但这个编码很少用于传输,其规则如同UTF-16

小端序UTF-32的BOM等同小端序UTF-16的BOM图案后面加上一个NUL字符,这是一个不寻常的例子,即BOM在两种不同的编码中是相同的形式。使用BOM来识别编码的程序员必须分辨文件是UTF-32编码还是单纯以NUL作为第一个字符。

不同编码的比特组顺序标记的表示

编码 表示(十六进位 表示(十进位
UTF-8 EF BB BF 239 187 191
UTF-16大端序 FE FF 254 255
UTF-16小端序 FF FE 255 254
UTF-32(大端序) 00 00 FE FF 0 0 254 255
UTF-32(小端序) FF FE 00 00 255 254 0 0
UTF-7 2B 2F 76和以下的一个比特组:[ 38 | 39 | 2B | 2F ] 43 47 118和以下的一个比特组:[ 56 | 57 | 43 | 47 ]
UTF-1 F7 64 4C 247 100 76
UTF-EBCDIC DD 73 66 73 221 115 102 115
Unicode标准压缩方案 0E FE FF 14 254 255
BOCU-1 FB EE 28 及可能跟随着FF 251 238 40 及可能跟随着255
GB-18030 84 31 95 33 132 49 149 51

另见

参考文献

  1. FAQ - UTF-8, UTF-16, UTF-32 & BOM. Unicode.org. [2017-01-28]. 
  2. The Unicode® Standard Version 9.0 (PDF). The Unicode Consortium. 
  3. The Unicode Standard 5.0, Chapter 2:General Structure (PDF): 36. [2009-03-29]. Table 2-4. The Seven Unicode Encoding Schemes 
  4. The Unicode Standard 5.0, Chapter 2:General Structure (PDF): 36. [2008-11-30]. 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 
  5. FAQ - UTF-8, UTF-16, UTF-32 & BOM: Can a UTF-8 data stream contain the BOM character (in UTF-8 form)? If yes, then can I still assume the remaining UTF-8 bytes are in big-endian order?. [2008-03-29]. 
  6. Re: pre-HTML5 and the BOM from Asmus Freytag on 2012-07-13 (Unicode Mail List Archive). Unicode.org. [2012-07-14]. 
  7. Bug ID: JDK-6378911 UTF-8 decoder handling of byte-order mark has changed. Bugs.sun.com. [2017-01-28]. 
  8. Yergeau, Francois. UTF-8, a transformation format of ISO 10646. IETF. 2003-11 [2014-05-15]. RFC 3629. 
  9. Alf P. Steinbach. Unicode part 1: Windows console i/o approaches. 2011 [2012-03-24]. However, since the C++ source code was encoded as UTF-8 without BOM (as is usual in Linux), the Visual C++ compiler erroneously assumed that the source code was encoded as Windows ANSI. 
  10. UTF-16LE. Encoding Standard. WHATWG. 
  11. Decode. Encoding Standard. WHATWG. 

外部链接