Skip to main content

6. Byte order mark (BOM) (字节顺序标记)

BOM的定义

UCS字符 U+FEFF "ZERO WIDTH NO-BREAK SPACE" (零宽不换行空格) 也被非正式地称为 "BYTE ORDER MARK" (字节顺序标记,缩写为"BOM")。

BOM的两种用途

用途1: 真正的零宽不换行空格

该字符可以在文本中用作真正的"零宽不换行空格"。

用途2: 字节流签名

BOM这个名称暗示了该字符的第二种可能用途:将U+FEFF字符放在UCS字符流的开头作为"签名"。

BOM作为签名的功能

这种序列化流的接收者可以使用初始字符作为提示:

  1. 标识流类型: 表明流由UCS字符组成
  2. 识别编码: 识别所涉及的UCS编码
  3. 识别字节序: 对于具有多八位字节编码单元的编码,识别八位字节的序列化顺序

UTF-8中的BOM

UTF-8 BOM的字节序列

UTF-8 BOM: EF BB BF

UTF-8具有单八位字节编码单元,因此识别字节序的功能是无用的,BOM将始终显示为八位字节序列 EF BB BF

⚠️ 使用BOM的注意事项

位置解释规则

出现在流开头以外任何位置的字符U+FEFF:

  • 必须 (MUST) 被解释为零宽不换行空格的语义
  • 不得 (MUST NOT) 被解释为签名

BOM剥离建议

当被解释为签名时,Unicode标准建议初始的U+FEFF字符可以在处理文本之前被剥离。

何时需要剥离?

在某些情况下,剥离是必要的:

  • 例如,连接两个字符串时
  • 否则,结果字符串可能在连接点包含意外的"零宽不换行空格"

剥离的影响

剥离可能会影响不同层的外部过程:

  • 数字签名
  • 字符计数
  • 这些过程依赖于流中所有字符的存在

建议做法

因此,建议 (RECOMMENDED)

  • 避免在没有充分理由的情况下剥离被解释为签名的初始U+FEFF
  • 在适当的时候忽略它而不是剥离它(例如用于显示)
  • 仅在真正必要时才剥离它

U+FEFF的歧义性

流的第一位置的U+FEFF 可以 (MAY) 被解释为零宽不换行空格,并不总是签名。

Unicode 3.2的改进

为了减少这种不确定性,Unicode 3.2添加了一个新字符:

U+2060 "WORD JOINER" (词连接符)

  • 具有与U+FEFF完全相同的语义和用法
  • 除了签名功能
  • 强烈建议专门使用它来表达词连接语义

最终,遵循此建议将使得几乎可以确定任何初始的U+FEFF都是签名,而不是预期的"零宽不换行空格"。

协议中BOM的使用限制

与此同时,不确定性仍然存在,并可能影响互联网协议。协议规范可以 (MAY) 限制U+FEFF作为签名的使用,以减少或消除这种不确定性的潜在不良影响。

建议的限制策略

为了在这些限制的优势(减少不确定性)和缺点(失去签名功能)之间取得平衡,区分几种情况是有用的:

情况1: 协议强制使用UTF-8的元素

协议应该 (SHOULD) 禁止对协议强制始终为UTF-8的文本协议元素使用U+FEFF作为签名,因为在这些情况下签名功能完全无用。

情况2: 协议提供字符编码识别机制的元素

当协议为某些文本协议元素提供字符编码识别机制时,如果预期协议的实现将始终能够正确使用这些机制,协议应该 (SHOULD) 也禁止对这些元素使用U+FEFF作为签名。

这种情况发生在:

  • 协议元素从创建到(正确标记的)传输期间都在实现的严格控制下

情况3: 协议不提供字符编码识别机制的元素

当以下情况时,协议不应该 (SHOULD NOT) 禁止对这些文本协议元素使用U+FEFF作为签名:

  • 协议不提供字符编码识别机制
  • 禁令将无法执行
  • 预期协议的实现将无法始终正确使用机制

后两种情况可能发生在较大的协议元素上,例如MIME实体,特别是当协议的实现将从以下来源获得此类实体时:

  • 文件系统
  • 没有有效负载编码识别机制的协议(如FTP)
  • 不保证正确识别字符编码的其他协议(如HTTP)

BOM处理规则总结

当协议禁止BOM时

当协议禁止某个协议元素使用U+FEFF作为签名时,该协议元素中的任何初始U+FEFF 必须 (MUST) 被解释为"零宽不换行空格"。

当协议不禁止BOM时

当协议不禁止某个协议元素使用U+FEFF作为签名时,实现应该 (SHOULD) 准备好处理该元素中的签名并做出适当反应:

  • 根据需要使用签名来识别字符编码
  • 根据情况剥离或忽略签名

UTF-8 BOM使用建议

场景建议理由
纯UTF-8文件❌ 不使用BOMUTF-8没有字节序问题
协议强制UTF-8❌ 禁止BOM签名功能无用
多编码环境⚠️ 谨慎使用可能导致兼容性问题
Windows记事本ℹ️ 自动添加遗留行为,应避免

实际示例

Windows记事本的BOM

文件内容 (十六进制):
EF BB BF 48 65 6C 6C 6F
BOM H e l l o

问题: 某些程序可能将BOM显示为乱码
解决方案: 使用更好的编辑器(VS Code, Sublime等)

网页中的BOM问题

<!-- 文件以BOM开始 -->
<!DOCTYPE html>
<html>
...

问题: BOM可能导致:
- HTTP头部已发送后无法设置cookie
- 输出缓冲问题
- 某些浏览器显示问题

解决方案: 移除BOM

相关链接