跳到主要内容

6. 字节序标记 (BOM)

定义

UCS 字符 U+FEFF "ZERO WIDTH NO-BREAK SPACE" 也非正式地称为 "BYTE ORDER MARK" (缩写为 "BOM"). 该字符可以在文本中作为真正的 "ZERO WIDTH NO-BREAK SPACE" 使用, 但 BOM 这个名称暗示了该字符的第二种可能用途: 在 UCS 字符流前置一个 U+FEFF 字符, 作为一种 "签名" (signature).

作为签名使用

这类序列化流的接收者随后可以把起始字符作为提示, 用于判断:

  • 该流由 UCS 字符组成
  • 涉及的是哪一种 UCS 编码
  • 对于具有多八位组编码单元的编码, 可据此识别八位组的序列化顺序

UTF-8 与 BOM

UTF-8 使用单八位组编码单元, 因此上述最后一种功能没有用处, BOM 将始终表现为八位组序列 EF BB BF.

解释规则

位置很重要

必须理解, 出现在流起始位置以外任何位置的字符 U+FEFF 必须按零宽非断行空格 (zero-width non-breaking space) 的语义解释, 不得被解释为签名.

移除时的考虑

当 U+FEFF 被解释为签名时, Unicode 标准建议可以在处理文本前移除起始的 U+FEFF 字符. 在某些情况下, 这种移除是必要的 (例如连接两个字符串时, 否则结果字符串可能在连接点包含一个非预期的 "ZERO WIDTH NO-BREAK SPACE"), 但它也可能影响不同层上的外部过程 (例如数字签名或字符计数), 因为这些过程依赖流中所有字符都存在.

建议

因此推荐:

  • 如果没有充分理由, 避免移除被解释为签名的起始 U+FEFF
  • 在适当时 (例如用于显示), 忽略它而不是移除它
  • 仅在确有必要时才移除它

歧义问题

位于流第一个位置的 U+FEFF 可以被解释为零宽非断行空格, 并不总是签名.

Unicode 3.2 新增字符

为了减小这种不确定性, Unicode 3.2 新增了字符 U+2060 "WORD JOINER", 除签名功能外, 它与 U+FEFF 具有完全相同的语义和用法, 并强烈建议只使用它来表达词连接语义.

未来的明确性

最终, 遵循这一建议将使人们几乎可以确定任何起始 U+FEFF 都是签名, 而不是有意使用的 "ZERO WIDTH NO-BREAK SPACE".

协议指南

与此同时, 遗憾的是这种不确定性仍然存在, 并可能影响 Internet 协议. 协议规范可以限制将 U+FEFF 用作签名, 以减少或消除这种不确定性可能产生的不良影响.

为了在此类限制的优点 (降低不确定性) 与缺点 (失去签名功能) 之间取得平衡, 区分以下几种情况是有用的:

情况 1: 强制使用 UTF-8

对于协议规定始终为 UTF-8 的文本协议元素, 协议应该禁止将 U+FEFF 用作签名, 因为签名功能在这些情况下完全没有用处.

情况 2: 可靠的识别机制

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

当协议元素从创建到其 (正确标记的) 传输期间一直严格处于实现控制之下时, 就属于这种情况.

情况 3: 没有识别机制

对于协议未提供字符编码识别机制的文本协议元素, 在以下情况下, 协议不应该禁止将 U+FEFF 用作签名:

  • 禁令无法执行, 或
  • 预期该协议的实现无法始终正确使用这些机制

后两种情况很可能出现在较大的协议元素中, 例如 MIME 实体, 尤其是当协议实现会从以下来源取得这些实体时:

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

实现指南

禁止时

当协议禁止在某个协议元素中将 U+FEFF 用作签名时, 该协议元素中的任何起始 U+FEFF 必须被解释为 "ZERO WIDTH NO-BREAK SPACE".

未禁止时

当协议并未禁止在某个协议元素中将 U+FEFF 用作签名时, 实现应该准备好:

  • 处理该元素中的签名
  • 适当作出反应: 必要时使用该签名识别字符编码
  • 视情况移除或忽略该签名

相关链接