编码

现行标准 — 最后更新

参与:
GitHub whatwg/encoding (新问题, 开放问题)
在 Matrix 上聊天
提交:
GitHub whatwg/encoding/commits
此提交的快照
@encodings
测试:
web-platform-tests encoding/ (正在进行的工作)
翻译 (非规范性)
日本語
简体中文
한국어

摘要

编码标准定义了编码及其 JavaScript API。

1. 前言

UTF-8 编码是交换 Unicode(通用编码字符集)最合适的编码。因此,对于新协议和格式,以及在新环境中部署的现有格式,本规范要求(并定义)使用 UTF-8 编码。

其他(旧)编码在过去某种程度上已经被定义。然而,用户代理并未始终以相同的方式实现它们,也未始终使用相同的标签,并且在处理编码的未定义和以前的专有区域时经常有所不同。本规范解决了这些差距,使得新的用户代理无需逆向工程编码实现,而现有的用户代理可以趋于一致。

特别是,本规范定义了所有这些编码、从字节到标量值及其返回的算法、它们的规范名称和识别标签。本规范还定义了一个 API,用于向 JavaScript 暴露部分编码算法。

用户代理在标签方面也显著偏离了 IANA 字符集注册表中列出的内容。为了阻止进一步传播旧编码,本规范对上述细节进行了详尽的定义,因此不需要注册表。特别是,本规范不提供扩展编码任何方面的机制。

2. 安全背景

当生产者和消费者对使用的编码或对给定编码的实现方式未达成一致时,会出现一系列编码安全问题。例如,2011 年报告了一次攻击,其中 Shift_JIS 的前导字节 0x82 被用来“掩盖” JSON 资源中某字段的尾随字节 0x22,该字段由攻击者控制。生产者未发现问题,尽管这是一个非法字节组合。消费者将其解码为单个 U+FFFD(�),因此改变了整体解释,因为 U+0022(")是一个重要的分隔符。现在,使用多个字节表示标量值的编码的解码器要求,在非法字节组合的情况下,范围 U+0000 到 U+007F(含)的标量值不能被“掩盖”。对于上述序列,输出将是 U+FFFD U+0022。(作为一个不幸的例外,gb18030 解码器将在 队列末尾最多“掩盖”一个这样的字节。)

对于将任何 ASCII 字节映射到非 ASCII 代码点的编码(当没有前导字节存在时),这是一个更大的问题。这些是“ASCII 不兼容”编码,除了由于已部署内容而必须支持的 ISO-2022-JPUTF-16BE/LE,它们不被支持。(正在 调查是否可以将更多此类编码的标签映射到 替代编码,而不是未知编码回退。)一个示例攻击是向资源注入精心设计的内容,然后鼓励用户覆盖编码,从而导致例如脚本执行。

HTML 和 HTML 表单功能中使用的 URL 编码器在使用无法表示所有标量值的编码时也可能导致轻微的信息丢失。例如,当资源使用 windows-1252 编码时,服务器将无法区分最终用户在表单中输入“💩”和“💩”。

当仅使用 UTF-8 时,这里概述的问题将消失,这也是现在所有事物必须使用 UTF-8 编码的众多原因之一。

另请参阅 浏览器 UI章节。

3. 术语

本规范依赖于 Infra 标准。[INFRA]

十六进制数字以 "0x" 为前缀。

在公式中,所有数字均为整数,加法用 "+" 表示,减法用 "−" 表示,乘法用 "×" 表示,整数除法用 "/" 表示(返回商),取模用 "%" 表示(返回整数除法的余数),逻辑左移用 "<<" 表示,逻辑右移用 ">>" 表示,按位与用 "&" 表示,按位或用 "|" 表示。

对于逻辑右移,操作数必须至少具有 21 位精度。


I/O 队列 是一种 列表,其 具有特定类型(例如 字节标量值)。队列末尾 是一种特殊的 ,可以存在于任何类型的 I/O 队列中,表示队列中没有更多的

使用 I/O 队列有两种方式:即时模式,用于表示存储在内存中的 I/O 数据;流模式,用于表示来自网络的数据。即时队列的最后一项是 队列末尾,而流队列不需要有它,因此它们的 读取操作可能会阻塞。

预计流式 I/O 队列将被创建为空,并且随着数据从网络进入,会将新的 推入队列。当底层网络流关闭时,应将一个 队列末尾推入队列。

由于从流式 I/O 队列读取可能会阻塞,因此流式 I/O 队列不应从 事件循环中使用,而应在 并行中使用。

要从 I/O 队列 ioQueue 读取一个 ,按以下步骤执行:

  1. 如果 ioQueue 为空,则等待直到其 长度 至少为 1。

  2. 如果 ioQueue[0] 是 队列结尾(end-of-queue),则返回 队列结尾

  3. 移除 ioQueue[0] 并返回它。

要从 ioQueue 中读取 number,请执行以下步骤:

  1. readItems 为 « »。

  2. 执行以下步骤 number 次:

    1. 追加readItems,结果为从 ioQueue 读取的一个项。

  3. 移除 队列末尾readItems

  4. 返回 readItems

要从 I/O 队列 ioQueue 窥视(peek) number,按以下步骤执行:

  1. 等待,直到 ioQueue长度等于或大于 number,或 ioQueue包含 队列结尾(end-of-queue),以先发生者为准。

  2. prefix 为 « »。

  3. 对于 区间 1 到 number(含),中的每个 n

    1. 如果 ioQueue[n] 是 队列结尾,则 跳出循环。

    2. 否则, ioQueue[n] 追加到 prefix

  4. 返回 prefix

要向 I/O 队列 ioQueue 推送一个 item,按以下步骤执行:

  1. 如果 ioQueue 的最后一个 队列结尾(end-of-queue)

    1. 如果 item 也是 队列结尾,则不做任何操作。

    2. 否则, ioQueue 的最后一个 之前插入 item

  2. 否则, item 追加到 ioQueue

I/O 队列 ioQueue 推送一系列项,是指按照给定顺序,将序列中的每一项依次推送到 ioQueue 中。

将一个 (非 队列结尾(end-of-queue)恢复I/O 队列中,即执行 列表前插(prepend)操作。将一个不含 队列结尾项列表恢复到 I/O 队列中,则按给定顺序将这些项插入到队列的第一个项之前。

如果向 I/O 队列 « 0x92 0xA9, 队列结尾 » 插入字节 « 0xF0, 0x9F », 则结果为 I/O 队列 « 0xF0, 0x9F, 0x92 0xA9, 队列结尾 »。下一个要读取的项是 0xF0。

转换一个 I/O 队列 ioQueue列表字符串字节序列,返回从 ioQueue 读取无限数量的结果。

转换一个列表字符串字节序列 inputI/O 队列,按照以下步骤操作:

  1. 断言input 不是 列表,或者其中不包含 队列结尾

  2. 返回一个 I/O 队列,其内容为 input 中的(按顺序),并在末尾加上 队列结尾

Infra 标准预计将定义一些关于类型转换的基础设施。详见 whatwg/infra issue #319[INFRA]

I/O 队列被定义为列表,而非队列,因为它们包含 恢复操作。然而,这一恢复操作仅是本规范算法的内部细节,不应被其他标准使用。实现可以采用其他方式来实现此类算法,细节见实现注意事项


要从代理对中获取一个 标量值,给定一个 前导代理 leading 和一个 尾随代理 trailing,返回 0x10000 + ((leading − 0xD800) << 10) + (trailing − 0xDC00)。


创建一个 Uint8Array 对象,给定一个 I/O 队列 ioQueuerealm realm

  1. bytes 为将 ioQueue 转换为字节序列的结果。

  2. 返回在 realm 中用 bytes 创建 Uint8Array 对象的结果。

4. 编码

编码定义了从标量值序列到字节序列(及其反向)的映射。每个编码都有一个名称,以及一个或多个标签

本规范定义了三个与 Unicode 标准中定义的编码方案同名的编码UTF-8UTF-16LEUTF-16BE。这些编码编码方案的不同之处在于字节顺序标记(也称为 BOM)的处理不是编码本身的一部分,而是本规范中包装算法的一部分,而字节顺序标记处理是 Unicode 标准中编码方案定义的一部分。UTF-8UTF-8 解码算法一起使用时,与同名的编码方案匹配。本规范不提供与UTF-16LEUTF-16BE结合以匹配类似名称的编码方案的包装算法。[UNICODE]

4.1. 编码器和解码器

每个编码都有一个关联的解码器,并且大多数都有一个关联的编码器解码器编码器的实例具有一个处理器算法,并可能具有状态。处理器算法接受一个输入I/O 队列和一个,并返回完成、一个或多个错误(可选地带有一个代码点),或继续

替代UTF-16BE/LE编码没有编码器

错误模式在以下使用中,对于解码器是"replacement"或"fatal",对于编码器是"fatal"或"html"。

XML 处理器会将错误模式设置为"fatal"。[XML]

由于 HTML 表单需要一个非终止的旧编码器,"html"作为错误模式存在。"html"错误模式会导致发出一个无法与合法输入区分的序列,因此可能导致静默的数据丢失。强烈建议开发人员使用UTF-8编码以防止这种情况发生。[HTML]


处理队列,给定一个编码解码器编码器实例encoderDecoderI/O 队列inputI/O 队列output错误模式mode

  1. 当条件为真时:

    1. result为通过以下步骤处理一个项的结果:从input读取encoderDecoderinputoutputmode

    2. 如果result不是继续,则返回result

处理一个项,给定一个item、一个编码编码器解码器实例encoderDecoderI/O 队列inputI/O 队列output错误模式mode

  1. 断言encoderDecoder不是一个编码器实例或mode不是"replacement"。

  2. 断言encoderDecoder不是一个解码器实例或mode不是"html"。

  3. 断言encoderDecoder不是一个编码器实例或item不是一个代理

  4. result为运行encoderDecoder处理器算法,输入为inputitem的结果。

  5. 如果result完成

    1. 推入队列末尾output

    2. 返回result

  6. 否则,如果result是一个或多个

    1. 断言encoderDecoder不是一个解码器实例或result不包含任何代理

    2. 推入resultoutput

  7. 否则,如果result是一个错误,根据mode运行相关步骤:

    "replacement"
    推入U+FFFD (�)到output
    "html"
    推入0x26 (&), 0x23 (#),后跟表示result代码点的最短十进制序列(范围为0x30 (0)到0x39 (9),含),最后是0x3B (;)到output
    "fatal"
    返回result
  8. 返回继续

4.2. 名称和标签

下表列出了所有编码及其标签,用户代理必须支持这些编码和标签。用户代理不得支持任何其他编码标签

对于每个编码,对其ASCII 小写化名称会生成其一个标签

作者必须使用UTF-8编码,并且必须使用其(ASCII 大小写不敏感)"utf-8"标签来标识它。

新协议和格式,以及在新环境中部署的现有格式,必须仅使用UTF-8编码。如果这些协议和格式需要公开编码名称标签,它们必须将其公开为"utf-8"。

要从字符串label获取编码,请执行以下步骤:

  1. 移除label中的任何前导和尾随ASCII 空白

  2. 如果label与下表中列出的任何标签ASCII 大小写不敏感匹配,则返回对应的编码;否则返回失败。

这是一个比Unicode 技术标准第 22 号第 1.4 节规定的更基本和更严格的将标签映射到编码的算法,因为这是与已部署内容兼容所必需的。

名称 标签
编码
UTF-8 "unicode-1-1-utf-8"
"unicode11utf8"
"unicode20utf8"
"utf-8"
"utf8"
"x-unicode20utf8"
旧单字节编码
IBM866 "866"
"cp866"
"csibm866"
"ibm866"
ISO-8859-2 "csisolatin2"
"iso-8859-2"
"iso-ir-101"
"iso8859-2"
"iso88592"
"iso_8859-2"
"iso_8859-2:1987"
"l2"
"latin2"
ISO-8859-3 "csisolatin3"
"iso-8859-3"
"iso-ir-109"
"iso8859-3"
"iso88593"
"iso_8859-3"
"iso_8859-3:1988"
"l3"
"latin3"
ISO-8859-4 "csisolatin4"
"iso-8859-4"
"iso-ir-110"
"iso8859-4"
"iso88594"
"iso_8859-4"
"iso_8859-4:1988"
"l4"
"latin4"
ISO-8859-5 "csisolatincyrillic"
"cyrillic"
"iso-8859-5"
"iso-ir-144"
"iso8859-5"
"iso88595"
"iso_8859-5"
"iso_8859-5:1988"
ISO-8859-6 "arabic"
"asmo-708"
"csiso88596e"
"csiso88596i"
"csisolatinarabic"
"ecma-114"
"iso-8859-6"
"iso-8859-6-e"
"iso-8859-6-i"
"iso-ir-127"
"iso8859-6"
"iso88596"
"iso_8859-6"
"iso_8859-6:1987"
ISO-8859-7 "csisolatingreek"
"ecma-118"
"elot_928"
"greek"
"greek8"
"iso-8859-7"
"iso-ir-126"
"iso8859-7"
"iso88597"
"iso_8859-7"
"iso_8859-7:1987"
"sun_eu_greek"
ISO-8859-8 "csiso88598e"
"csisolatinhebrew"
"hebrew"
"iso-8859-8"
"iso-8859-8-e"
"iso-ir-138"
"iso8859-8"
"iso88598"
"iso_8859-8"
"iso_8859-8:1988"
"visual"
ISO-8859-8-I "csiso88598i"
"iso-8859-8-i"
"logical"
ISO-8859-10 "csisolatin6"
"iso-8859-10"
"iso-ir-157"
"iso8859-10"
"iso885910"
"l6"
"latin6"
ISO-8859-13 "iso-8859-13"
"iso8859-13"
"iso885913"
ISO-8859-14 "iso-8859-14"
"iso8859-14"
"iso885914"
ISO-8859-15 "csisolatin9"
"iso-8859-15"
"iso8859-15"
"iso885915"
"iso_8859-15"
"l9"
ISO-8859-16 "iso-8859-16"
KOI8-R "cskoi8r"
"koi"
"koi8"
"koi8-r"
"koi8_r"
KOI8-U "koi8-ru"
"koi8-u"
macintosh "csmacintosh"
"mac"
"macintosh"
"x-mac-roman"
windows-874 "dos-874"
"iso-8859-11"
"iso8859-11"
"iso885911"
"tis-620"
"windows-874"
windows-1250 "cp1250"
"windows-1250"
"x-cp1250"
windows-1251 "cp1251"
"windows-1251"
"x-cp1251"
windows-1252

参见下文了解与历史上的“Latin1”和“ASCII”概念的关系。

"ansi_x3.4-1968"
"ascii"
"cp1252"
"cp819"
"csisolatin1"
"ibm819"
"iso-8859-1"
"iso-ir-100"
"iso8859-1"
"iso88591"
"iso_8859-1"
"iso_8859-1:1987"
"l1"
"latin1"
"us-ascii"
"windows-1252"
"x-cp1252"
windows-1253 "cp1253"
"windows-1253"
"x-cp1253"
windows-1254 "cp1254"
"csisolatin5"
"iso-8859-9"
"iso-ir-148"
"iso8859-9"
"iso88599"
"iso_8859-9"
"iso_8859-9:1989"
"l5"
"latin5"
"windows-1254"
"x-cp1254"
windows-1255 "cp1255"
"windows-1255"
"x-cp1255"
windows-1256 "cp1256"
"windows-1256"
"x-cp1256"
windows-1257 "cp1257"
"windows-1257"
"x-cp1257"
windows-1258 "cp1258"
"windows-1258"
"x-cp1258"
x-mac-cyrillic "x-mac-cyrillic"
"x-mac-ukrainian"
旧多字节中文(简体)编码
GBK "chinese"
"csgb2312"
"csiso58gb231280"
"gb2312"
"gb_2312"
"gb_2312-80"
"gbk"
"iso-ir-58"
"x-gbk"
gb18030 "gb18030"
旧多字节中文(繁体)编码
Big5 "big5"
"big5-hkscs"
"cn-big5"
"csbig5"
"x-x-big5"
旧多字节日语编码
EUC-JP "cseucpkdfmtjapanese"
"euc-jp"
"x-euc-jp"
ISO-2022-JP "csiso2022jp"
"iso-2022-jp"
Shift_JIS "csshiftjis"
"ms932"
"ms_kanji"
"shift-jis"
"shift_jis"
"sjis"
"windows-31j"
"x-sjis"
旧多字节韩语编码
EUC-KR "cseuckr"
"csksc56011987"
"euc-kr"
"iso-ir-149"
"korean"
"ks_c_5601-1987"
"ks_c_5601-1989"
"ksc5601"
"ksc_5601"
"windows-949"
旧杂项编码
replacement "csiso2022kr"
"hz-gb-2312"
"iso-2022-cn"
"iso-2022-cn-ext"
"iso-2022-kr"
"replacement"
UTF-16BE "unicodefffe"
"utf-16be"
UTF-16LE "csunicode"
"iso-10646-ucs-2"
"ucs-2"
"unicode"
"unicodefeff"
"utf-16"
"utf-16le"
x-user-defined "x-user-defined"

所有编码及其标签也可以作为非规范性的encodings.json资源获取。

支持的编码集主要基于本标准开发开始时主要浏览器引擎支持的编码集的交集,同时移除了那些很少被合法使用但可能被用于攻击的编码。从现有 Web 内容的使用水平的零散证据来看,某些编码的包含是值得怀疑的。也就是说,虽然这些编码被浏览器广泛支持,但尚不清楚它们是否被 Web 内容广泛使用。然而,并未积极移除那些被浏览器广泛支持或属于 ISO 8859 系列的单字节编码。特别是,IBM866macintoshx-mac-cyrillicISO-8859-3ISO-8859-10ISO-8859-14ISO-8859-16的必要性对于支持现有内容来说是值得怀疑的,但目前没有移除这些编码的计划。

windows-1252编码有多个标签,例如"latin1"、"iso-8859-1"和"ascii",这些标签在历史上对开发人员来说一直很困惑。在 Web 上以及任何希望通过实现本标准与 Web 兼容的软件中,这些标签是同义词:"latin1"和"ascii"只是windows-1252的标签,任何遵循本标准的软件,例如,在请求“Latin1”或“ASCII”解码该字节时,会将 0x80 解码为 U+20AC (€)。

不遵循本标准的软件并不总是给出相同的答案。这一问题的根源在于最初指定 Latin1 的文档(ISO/IEC 8859-1)未为字节范围 0x00 到 0x1F 或 0x7F 到 0x9F 提供任何映射。同样,最初指定 ASCII 的文档(ISO/IEC 646 等)未为字节范围 0x80 到 0xFF 提供任何映射。这意味着在请求使用 Latin1 或 ASCII 编码时,不同的软件为这些字节选择了不同的代码点映射。Web 浏览器和与浏览器兼容的软件选择根据windows-1252映射这些字节,windows-1252 是两者的超集,这一选择已在本标准中被规范化。其他软件会抛出错误,或使用同构解码或其他映射。[ISO8859-1][ISO646]

因此,实施者和开发人员在使用以“Latin1”或“ASCII”为术语的 API 的库时需要格外小心。如果这些库为原始规范中未定义的字节选择了其他行为,则它们很可能不会给出符合本标准的答案。

4.3. 输出编码

要从编码encoding获取输出编码,请执行以下步骤:

  1. 如果encoding替代UTF-16BE/LE,则返回UTF-8

  2. 返回encoding

获取输出编码算法对于 URL 解析和 HTML 表单提交非常有用,因为两者都需要完全符合此算法。

5. 索引

大多数旧的编码都使用索引。一个索引是一个有序的条目列表,每个条目由一个指针和一个对应的代码点组成。在一个索引中,指针是唯一的,而代码点可以重复。

一个高效的实现可能为每个编码提供两个索引。一个针对其解码器优化,另一个针对其编码器优化。

要在一个索引中找到指针及其对应的代码点,请执行以下步骤:令lines为将资源内容按 U+000A LF 分割的结果。然后移除lines中为空字符串或以 U+0023 (#) 开头的每一项。然后通过将lines中的每一项按 U+0009 TAB 分割来找到指针及其对应的代码点。第一个子项是指针(作为十进制数),第二个是对应的代码点(作为十六进制数)。其他子项不相关。

为了表示变化,一个索引包括一个标识符和一个日期。如果标识符发生变化,则索引也发生变化。

索引代码点indexpointer对应的代码点,如果pointer不在index中,则为 null。

索引指针indexcodePoint对应的第一个指针,如果codePoint不在index中,则为 null。

除了GB18030 范围索引ISO-2022-JP 片假名索引外,每个索引都有一个非规范性的可视化。JIS0208 索引也有一个替代的Shift_JIS可视化。此外,除了GB18030 范围索引ISO-2022-JP 片假名索引外,每个索引的基本多语言平面覆盖范围也有可视化。

可视化的图例如下:

以下是本规范定义的索引,不包括单字节索引,后者有自己的表格:

索引 备注
Big5 索引 index-big5.txt Big5 索引可视化 Big5 索引 BMP 覆盖范围 与 Big5 标准结合香港补充字符集及其他常见扩展相匹配。
EUC-KR 索引 index-euc-kr.txt EUC-KR 索引可视化 EUC-KR 索引 BMP 覆盖范围 与 KS X 1001 标准和统一韩文代码(通常称为 Windows 代码页 949)相匹配。完全覆盖 Unicode 的韩文音节块。可视化中左上角位于指针 9026 的韩文块按 Unicode 顺序排列。单独来看,此索引中的其余韩文音节也按 Unicode 顺序排列。
GB18030 索引 index-gb18030.txt GB18030 索引可视化 GB18030 索引 BMP 覆盖范围 与 GB18030-2022 标准中编码为两个字节的代码点相匹配,但 0xA3 0xA0 映射到 U+3000 IDEOGRAPHIC SPACE 以与已部署内容兼容。此索引完全覆盖 Unicode 的 CJK 统一表意文字块。可视化中位于(第一个)U+3000 上方或左侧的该块中的条目按 Unicode 顺序排列。
GB18030 范围索引 index-gb18030-ranges.txt 索引的工作方式与其他所有索引不同。列出所有代码点将导致超过一百万个条目,而它们可以整齐地表示为 207 个范围,并结合简单的限制检查。因此,它仅在表面上与 GB18030-2000 标准中编码为四个字节的代码点相匹配。GB18030-2005 修订版的更改由伴随此索引的下文GB18030 范围索引代码点GB18030 范围索引指针算法内联处理。而 GB18030-2022 修订版的更改则再次以不同方式处理,以避免进一步增加映射到专用使用代码点的字节序列数量。相关的专用使用代码点在GB18030 编码器中通过一个旁表直接映射,以保持与它们之前映射方式的兼容性。
JIS0208 索引 index-jis0208.txt JIS0208 索引可视化, Shift_JIS 可视化 JIS0208 索引 BMP 覆盖范围 这是 JIS X 0208 标准,包括以前来自 IBM 和 NEC 的专有扩展。
JIS0212 索引 index-jis0212.txt JIS0212 索引可视化 JIS0212 索引 BMP 覆盖范围 这是 JIS X 0212 标准。由于在其他地方缺乏广泛支持,它仅由EUC-JP 解码器使用。
ISO-2022-JP 片假名索引 index-iso-2022-jp-katakana.txt 根据 Unicode 规范化形式 KC,这将半角片假名映射到全角片假名,但 U+FF9E (゙) 和 U+FF9F (゚) 映射到 U+309B (゛) 和 U+309C (゜),而不是 U+3099 (◌゙) 和 U+309A (◌゚)。它仅由ISO-2022-JP 编码器使用。[UNICODE]

GB18030 范围索引代码点是针对pointer的以下步骤的返回值:

  1. 如果pointer大于 39419 且小于 189000,或者pointer大于 1237575,则返回 null。

  2. 如果pointer是 7457,则返回代码点 U+E7C7。

  3. offsetGB18030 范围索引中小于或等于pointer的最后一个指针,并令codePointOffset为其对应的代码点。

  4. 返回一个代码点,其值为codePointOffset + pointeroffset

GB18030 范围索引指针是针对codePoint的以下步骤的返回值:

  1. 如果codePoint是 U+E7C7,则返回指针 7457。

  2. offsetGB18030 范围索引中小于或等于codePoint的最后一个代码点,并令pointerOffset为其对应的指针。

  3. 返回一个指针,其值为pointerOffset + codePointoffset

Shift_JIS 索引指针是针对codePoint的以下步骤的返回值:

  1. indexJIS0208 索引,排除所有指针在 8272 到 8835(含)范围内的条目。

    JIS0208 索引包含重复的代码点,因此排除这些条目会导致使用后面的代码点。

  2. 返回indexcodePoint索引指针

Big5 索引指针是针对codePoint的以下步骤的返回值:

  1. indexBig5 索引,排除所有指针小于 (0xA1 - 0x81) × 157 的条目。

    避免直接返回香港增补字符集扩展。

  2. 如果codePoint是 U+2550 (═)、U+255E (╞)、U+2561 (╡)、U+256A (╪)、U+5341 (十) 或 U+5345 (卅),则返回index中与codePoint对应的最后一个指针。

    还有其他重复的代码点,但对于那些代码点,应使用第一个指针。

  3. 返回indexcodePoint索引指针


所有索引也可以作为非规范性的indexes.json资源获取。(GB18030 范围索引在此处采用稍有不同的格式,以便表示范围。)

6. 为标准提供的挂钩

下面定义的算法(UTF-8 解码不带 BOM 的 UTF-8 解码不带 BOM 或失败的 UTF-8 解码以及UTF-8 编码)旨在供其他标准使用。

对于解码,新格式应使用UTF-8 解码。对于格式或协议中的标识符或字节序列,请使用不带 BOM 的 UTF-8 解码不带 BOM 或失败的 UTF-8 解码

对于编码,应使用UTF-8 编码

标准应确保它们传递给UTF-8 编码(以及旧的编码)的输入 I/O 队列实际上是标量值的 I/O 队列,即它们不包含代理项

这些挂钩(以及解码编码)将阻塞,直到输入 I/O 队列被完全消耗。为了在使用输出令牌时将其推入流中,调用者应使用空的输出 I/O 队列调用挂钩,并并行地从中读取。请注意,在使用不带 BOM 或失败的 UTF-8 解码时需要小心,因为在解码过程中发现的任何错误都将阻止队列末尾项被推入输出 I/O 队列。

要对字节的 I/O 队列ioQueue进行UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:

  1. buffer为从ioQueue窥视三个字节并转换为字节序列的结果。

  2. 如果buffer是 0xEF 0xBB 0xBF,则从ioQueue读取三个字节。(不对这些字节执行任何操作。)

  3. 使用UTF-8解码器实例、ioQueueoutput和"replacement"处理队列

  4. 返回output

要对字节的 I/O 队列ioQueue进行不带 BOM 的 UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:

  1. 使用UTF-8解码器实例、ioQueueoutput和"replacement"处理队列

  2. 返回output

要对字节的 I/O 队列ioQueue进行不带 BOM 或失败的 UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:

  1. potentialError为使用UTF-8解码器实例、ioQueueoutput和"fatal"处理队列的结果。

  2. 如果potentialError是一个错误,则返回失败。

  3. 返回output


要对标量值的 I/O 队列ioQueue进行UTF-8 编码,给定一个可选的字节 I/O 队列output(默认为 « »),返回使用UTF-8编码和output编码ioQueue的结果。

6.1. 为标准提供的旧版挂钩

强烈建议标准不要使用解码BOM 嗅探编码,除非为了兼容性需要。需要这些旧版挂钩的标准很可能还需要使用获取编码(将标签转换为编码)和获取输出编码(将一个编码转换为适合传递给编码的另一个编码)。

对于 URL 百分号编码这种极其特殊的情况,需要自定义编码器错误处理。应使用获取编码器编码或失败算法。其他算法不应直接使用。

要对字节的 I/O 队列ioQueue进行解码,给定一个备用编码encoding和一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:

  1. BOMEncoding为对ioQueue进行BOM 嗅探的结果。

  2. 如果BOMEncoding不为 null:

    1. encoding设置为BOMEncoding

    2. 如果BOMEncodingUTF-8,则从ioQueue读取三个字节;否则读取两个字节。(不对这些字节执行任何操作。)

    为了与已部署内容兼容,字节顺序标记比任何其他东西都更具权威性。在使用 HTTP 的上下文中,这违反了 `Content-Type` 标头的语义。

  3. 使用encoding解码器实例、ioQueueoutput和"replacement"处理队列

  4. 返回output

要对字节的 I/O 队列ioQueue进行BOM 嗅探,请执行以下步骤:

  1. BOM为从ioQueue窥视 3 个字节并转换为字节序列的结果。

  2. 对于下表中的每一行,从第一行开始向下,如果BOM第一列中给出的字节开头,则返回该行第二列单元格中给出的编码。否则,返回 null。

    字节顺序标记 编码
    0xEF 0xBB 0xBF UTF-8
    0xFE 0xFF UTF-16BE
    0xFF 0xFE UTF-16LE

此挂钩是一个变通方法,因为解码无法向调用者传达它已找到字节顺序标记,因此未使用提供的编码。此挂钩应在解码之前调用,它将返回与找到的字节顺序标记对应的编码,否则返回 null。


要对标量值的 I/O 队列ioQueue进行编码,给定一个编码encoding和一个可选的字节 I/O 队列output(默认为 « »),请执行以下步骤:

  1. encoder为从encoding获取编码器的结果。

  2. 使用encoderioQueueoutput和"html"处理队列

  3. 返回output

这是 HTML 表单的旧版挂钩。在其上层叠UTF-8 编码是安全的,因为它从不触发错误[HTML]


要从编码encoding获取编码器

  1. 断言encoding不是替代UTF-16BE/LE

  2. 返回encoding编码器实例。

要对标量值的 I/O 队列ioQueue进行编码或失败,给定一个编码器实例encoder和一个字节 I/O 队列output,请执行以下步骤:

  1. potentialError为使用encoderioQueueoutput和"fatal"处理队列的结果。

  2. 队列末尾推入output

  3. 如果potentialError是一个错误,则返回错误代码点

  4. 返回 null。

这是 URL 百分号编码的旧版挂钩。调用者必须保持一个编码器实例的活动状态,因为ISO-2022-JP 编码器在返回错误时可能处于两种不同状态之一。这也意味着,如果调用者以某种方式发出字节来编码错误,这些字节必须在 0x00 到 0x7F(含)的范围内,不包括 0x0E、0x0F、0x1B、0x5C 和 0x7E。[URL]

特别是,如果在返回错误时,ISO-2022-JP 编码器处于罗马状态,调用者不能输出 0x5C (\),因为它不会被解码为 U+005C (\)。因此,将编码或失败用于非预期目的的应用程序应注意防止将ISO-2022-JP 编码器与替换方案(例如 JavaScript 和 CSS 的替换方案)结合使用,这些方案使用 U+005C (\) 作为替换语法的一部分(例如,\u2603),或者确保将替换语法通过编码器传递(与 URL 百分号编码相反)。

返回值要么是表示无法编码的代码点的数字,要么是 null(如果没有错误)。当它返回非 null 时,调用者将必须再次调用它,提供相同的编码器实例和一个新的输出 I/O 队列。

7. API

本节使用 Web IDL 的术语。浏览器用户代理必须支持此 API。JavaScript 实现应支持此 API。鼓励其他用户代理或编程语言使用适合其需求的 API,可能不是这一个。[WEBIDL]

以下示例使用 TextEncoder 对象将字符串数组编码为 ArrayBuffer。结果是一个 Uint8Array,其中包含字符串的数量(作为 Uint32Array),后跟第一个字符串的长度(作为 Uint32Array)、UTF-8 编码的字符串数据、第二个字符串的长度(作为 Uint32Array)、字符串数据,依此类推。

function encodeArrayOfStrings(strings) {
          var encoder, encoded, len, bytes, view, offset;
        
          encoder = new TextEncoder();
          encoded = [];
        
          len = Uint32Array.BYTES_PER_ELEMENT;
          for (var i = 0; i < strings.length; i++) {
            len += Uint32Array.BYTES_PER_ELEMENT;
            encoded[i] = encoder.encode(strings[i]);
            len += encoded[i].byteLength;
          }
        
          bytes = new Uint8Array(len);
          view = new DataView(bytes.buffer);
          offset = 0;
        
          view.setUint32(offset, strings.length);
          offset += Uint32Array.BYTES_PER_ELEMENT;
          for (var i = 0; i < encoded.length; i += 1) {
            len = encoded[i].byteLength;
            view.setUint32(offset, len);
            offset += Uint32Array.BYTES_PER_ELEMENT;
            bytes.set(encoded[i], offset);
            offset += len;
          }
          return bytes.buffer;
        }

以下示例将包含由前一个示例生成的格式编码的数据的 ArrayBuffer(或用于非 UTF-8 编码的等效算法)解码回字符串数组。

function decodeArrayOfStrings(buffer, encoding) {
          var decoder, view, offset, num_strings, strings, len;
        
          decoder = new TextDecoder(encoding);
          view = new DataView(buffer);
          offset = 0;
          strings = [];
        
          num_strings = view.getUint32(offset);
          offset += Uint32Array.BYTES_PER_ELEMENT;
          for (var i = 0; i < num_strings; i++) {
            len = view.getUint32(offset);
            offset += Uint32Array.BYTES_PER_ELEMENT;
            strings[i] = decoder.decode(
              new DataView(view.buffer, offset, len));
            offset += len;
          }
          return strings;
        }

7.1. 接口混入 TextDecoderCommon

interface mixin TextDecoderCommon {
          readonly attribute DOMString encoding;
          readonly attribute boolean fatal;
          readonly attribute boolean ignoreBOM;
        };
        

TextDecoderCommon 接口混入定义了 TextDecoderTextDecoderStream 对象共享的通用 getter。这些对象有关联的:

编码
一个编码
解码器
一个解码器实例。
I/O 队列
一个字节的I/O 队列
忽略 BOM
一个布尔值,初始为 false。
已见 BOM
一个布尔值,初始为 false。
错误模式
一个错误模式,初始为 "replacement"。

序列化 I/O 队列算法,给定一个 TextDecoderCommon decoder 和一个标量值的I/O 队列 ioQueue,运行以下步骤:

  1. output 为空字符串。

  2. 当为真时:

    1. item 为从 ioQueue 读取的结果。

    2. 如果 item队列末尾,则返回 output

    3. 如果 decoder编码UTF-8UTF-16BE/LE,并且 decoder忽略 BOM已见 BOM均为 false:

      1. decoder已见 BOM设置为 true。

      2. 如果 item 是 U+FEFF BOM,则继续

    4. item 附加到 output

该算法在 BOM 处理方面与平台其余部分使用的解码算法故意不同,以便为 API 用户提供更多控制。


encoding getter 的步骤是返回this编码名称,并ASCII 小写化

fatal getter 的步骤是:如果this错误模式是 "fatal",则返回 true;否则返回 false。

ignoreBOM getter 的步骤是返回this忽略 BOM

7.2. 接口 TextDecoder

dictionary TextDecoderOptions {
  boolean fatal = false;
  boolean ignoreBOM = false;
};

dictionary TextDecodeOptions {
  boolean stream = false;
};

[Exposed=*]
interface TextDecoder {
  constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options = {});

  USVString decode(optional AllowSharedBufferSource input, optional TextDecodeOptions options = {});
};
TextDecoder includes TextDecoderCommon;

一个 TextDecoder 对象拥有一个关联的不刷新标志(do not flush flag),它是一个布尔值, 初始为 false。

decoder = new TextDecoder([label = "utf-8" [, options]])

返回一个新的 TextDecoder 对象。

如果 label 不是一个有效的标签,或者是用于 replacement 的标签,则抛出一个