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-JP 和 UTF-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 队列 ioQueue 读取一个 项,按以下步骤执行:
-
如果 ioQueue[0] 是 队列结尾(end-of-queue),则返回 队列结尾。
-
移除 ioQueue[0] 并返回它。
要从 ioQueue 中读取 number 个 项,请执行以下步骤:
向 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。
Infra 标准预计将定义一些关于类型转换的基础设施。详见 whatwg/infra issue #319。[INFRA]
I/O 队列被定义为列表,而非队列,因为它们包含 恢复操作。然而,这一恢复操作仅是本规范算法的内部细节,不应被其他标准使用。实现可以采用其他方式来实现此类算法,细节见实现注意事项。
要从代理对中获取一个 标量值,给定一个 前导代理 leading 和一个 尾随代理 trailing,返回 0x10000 + ((leading − 0xD800) << 10) + (trailing − 0xDC00)。
要创建一个
Uint8Array
对象,给定一个 I/O 队列 ioQueue 和 realm realm:
-
令 bytes 为将 ioQueue 转换为字节序列的结果。
-
返回在 realm 中用 bytes 创建
Uint8Array
对象的结果。
4. 编码
编码定义了从标量值序列到字节序列(及其反向)的映射。每个编码都有一个名称,以及一个或多个标签。
本规范定义了三个与 Unicode 标准中定义的编码方案同名的编码:UTF-8、UTF-16LE和UTF-16BE。这些编码与编码方案的不同之处在于字节顺序标记(也称为 BOM)的处理不是编码本身的一部分,而是本规范中包装算法的一部分,而字节顺序标记处理是 Unicode 标准中编码方案定义的一部分。UTF-8与UTF-8 解码算法一起使用时,与同名的编码方案匹配。本规范不提供与UTF-16LE和UTF-16BE结合以匹配类似名称的编码方案的包装算法。[UNICODE]
4.1. 编码器和解码器
每个编码都有一个关联的解码器,并且大多数都有一个关联的编码器。解码器和编码器的实例具有一个处理器算法,并可能具有状态。处理器算法接受一个输入I/O 队列和一个项,并返回完成、一个或多个项、错误(可选地带有一个代码点),或继续。
错误模式在以下使用中,对于解码器是"replacement
"或"fatal
",对于编码器是"fatal
"或"html
"。
由于 HTML 表单需要一个非终止的旧编码器,"html
"作为错误模式存在。"html
"错误模式会导致发出一个无法与合法输入区分的序列,因此可能导致静默的数据丢失。强烈建议开发人员使用UTF-8编码以防止这种情况发生。[HTML]
要处理一个项,给定一个项item、一个编码的编码器或解码器实例encoderDecoder、I/O 队列input、I/O 队列output和错误模式mode:
4.2. 名称和标签
下表列出了所有编码及其标签,用户代理必须支持这些编码和标签。用户代理不得支持任何其他编码或标签。
对于每个编码,对其ASCII 小写化的名称会生成其一个标签。
作者必须使用UTF-8编码,并且必须使用其(ASCII
大小写不敏感)"utf-8
"标签来标识它。
新协议和格式,以及在新环境中部署的现有格式,必须仅使用UTF-8编码。如果这些协议和格式需要公开编码的名称或标签,它们必须将其公开为"utf-8
"。
要从字符串label获取编码,请执行以下步骤:
-
移除label中的任何前导和尾随ASCII 空白。
-
如果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 系列的单字节编码。特别是,IBM866、macintosh、x-mac-cyrillic、ISO-8859-3、ISO-8859-10、ISO-8859-14和ISO-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获取输出编码,请执行以下步骤:
-
如果encoding是替代或UTF-16BE/LE,则返回UTF-8。
-
返回encoding。
获取输出编码算法对于 URL 解析和 HTML 表单提交非常有用,因为两者都需要完全符合此算法。
5. 索引
大多数旧的编码都使用索引。一个索引是一个有序的条目列表,每个条目由一个指针和一个对应的代码点组成。在一个索引中,指针是唯一的,而代码点可以重复。
一个高效的实现可能为每个编码提供两个索引。一个针对其解码器优化,另一个针对其编码器优化。
要在一个索引中找到指针及其对应的代码点,请执行以下步骤:令lines为将资源内容按 U+000A LF 分割的结果。然后移除lines中为空字符串或以 U+0023 (#) 开头的每一项。然后通过将lines中的每一项按 U+0009 TAB 分割来找到指针及其对应的代码点。第一个子项是指针(作为十进制数),第二个是对应的代码点(作为十六进制数)。其他子项不相关。
为了表示变化,一个索引包括一个标识符和一个日期。如果标识符发生变化,则索引也发生变化。
索引代码点是index中pointer对应的代码点,如果pointer不在index中,则为 null。
索引指针是index中codePoint对应的第一个指针,如果codePoint不在index中,则为 null。
除了GB18030 范围索引和ISO-2022-JP 片假名索引外,每个索引都有一个非规范性的可视化。JIS0208 索引也有一个替代的Shift_JIS可视化。此外,除了GB18030 范围索引和ISO-2022-JP 片假名索引外,每个索引的基本多语言平面覆盖范围也有可视化。
可视化的图例如下:
- 未映射
- UTF-8 中的两个字节
- UTF-8 中的两个字节,代码点紧接前一个指针的代码点
- UTF-8 中的三个字节(非 PUA)
- UTF-8 中的三个字节(非 PUA),代码点紧接前一个指针的代码点
- 专用使用
- 专用使用,代码点紧接前一个指针的代码点
- UTF-8 中的四个字节
- UTF-8 中的四个字节,代码点紧接前一个指针的代码点
- 重复代码点已在较早的索引中映射
- CJK 兼容表意文字
- CJK 统一表意文字扩展 A
以下是本规范定义的索引,不包括单字节索引,后者有自己的表格:
索引 | 备注 | |||
---|---|---|---|---|
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的以下步骤的返回值:
-
如果pointer大于 39419 且小于 189000,或者pointer大于 1237575,则返回 null。
-
如果pointer是 7457,则返回代码点 U+E7C7。
-
令offset为GB18030 范围索引中小于或等于pointer的最后一个指针,并令codePointOffset为其对应的代码点。
-
返回一个代码点,其值为codePointOffset + pointer − offset。
GB18030 范围索引指针是针对codePoint的以下步骤的返回值:
-
如果codePoint是 U+E7C7,则返回指针 7457。
-
令offset为GB18030 范围索引中小于或等于codePoint的最后一个代码点,并令pointerOffset为其对应的指针。
-
返回一个指针,其值为pointerOffset + codePoint − offset。
Shift_JIS 索引指针是针对codePoint的以下步骤的返回值:
-
令index为JIS0208 索引,排除所有指针在 8272 到 8835(含)范围内的条目。
JIS0208 索引包含重复的代码点,因此排除这些条目会导致使用后面的代码点。
-
返回index中codePoint的索引指针。
Big5 索引指针是针对codePoint的以下步骤的返回值:
所有索引也可以作为非规范性的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(默认为 « »),请执行以下步骤:
要对字节的 I/O 队列ioQueue进行不带 BOM 的 UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
要对字节的 I/O 队列ioQueue进行不带 BOM 或失败的 UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
6.1. 为标准提供的旧版挂钩
强烈建议标准不要使用解码、BOM 嗅探和编码,除非为了兼容性需要。需要这些旧版挂钩的标准很可能还需要使用获取编码(将标签转换为编码)和获取输出编码(将一个编码转换为适合传递给编码的另一个编码)。
对于 URL 百分号编码这种极其特殊的情况,需要自定义编码器错误处理。应使用获取编码器和编码或失败算法。其他算法不应直接使用。
要对字节的 I/O 队列ioQueue进行解码,给定一个备用编码encoding和一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
要对字节的 I/O 队列ioQueue进行BOM 嗅探,请执行以下步骤:
-
令BOM为从ioQueue窥视 3 个字节并转换为字节序列的结果。
-
对于下表中的每一行,从第一行开始向下,如果BOM以第一列中给出的字节开头,则返回该行第二列单元格中给出的编码。否则,返回 null。
字节顺序标记 编码 0xEF 0xBB 0xBF UTF-8 0xFE 0xFF UTF-16BE 0xFF 0xFE UTF-16LE
此挂钩是一个变通方法,因为解码无法向调用者传达它已找到字节顺序标记,因此未使用提供的编码。此挂钩应在解码之前调用,它将返回与找到的字节顺序标记对应的编码,否则返回 null。
要对标量值的 I/O 队列ioQueue进行编码,给定一个编码encoding和一个可选的字节 I/O 队列output(默认为 « »),请执行以下步骤:
要从编码encoding获取编码器:
-
断言:encoding不是替代或UTF-16BE/LE。
-
返回encoding的编码器实例。
要对标量值的 I/O 队列ioQueue进行编码或失败,给定一个编码器实例encoder和一个字节 I/O 队列output,请执行以下步骤:
-
令potentialError为使用encoder、ioQueue、output和"
fatal
"处理队列的结果。 -
返回 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
接口混入定义了 TextDecoder
和 TextDecoderStream
对象共享的通用 getter。这些对象有关联的:
- 编码
- 一个编码。
- 解码器
- 一个解码器实例。
- I/O 队列
- 一个字节的I/O 队列。
- 忽略 BOM
- 一个布尔值,初始为 false。
- 已见 BOM
- 一个布尔值,初始为 false。
- 错误模式
- 一个错误模式,初始为
"
replacement
"。
序列化 I/O
队列算法,给定一个 TextDecoderCommon
decoder 和一个标量值的I/O 队列 ioQueue,运行以下步骤:
-
令 output 为空字符串。
-
当为真时:
该算法在 BOM 处理方面与平台其余部分使用的解码算法故意不同,以便为 API 用户提供更多控制。
7.2. 接口 TextDecoder
dictionary {
TextDecoderOptions boolean =
fatal false ;boolean =
ignoreBOM false ; };dictionary {
TextDecodeOptions boolean =
stream false ; }; [Exposed=*]interface {
TextDecoder constructor (optional DOMString = "utf-8",
label 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 的标签,则抛出一个