UTF-8000:无限制的UTF-8

Hacker News Top 工具

摘要

UTF-8000 是对UTF-8的一个提议扩展,允许任意大的编码单元,同时保留UTF-8的特性,作为一个独立项目呈现,并附有参考实现。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/09/20 09:31

# UTF-8000 来源:https://utf-8000.jb2170.com/ 无限 UTF-8! ASCII ⊆ UTF-8 ⊆ UTF-8000。 无特殊情形引入。 保留所有属性 (https://utf-8000.jb2170.com/#sec-properties)。 使用 `$ pipx install UTF-8000` 尝试参考实现 (https://utf-8000.jb2170.com/#sec-reference-implementation)。 UTF-8000 绝非由 Unicode 联盟 (https://home.unicode.org/) 认可或代表。 这是一个有趣的独立项目 / 提案。 ## TLDR / 示例 **ASCII** 1 `0xxxxxxx` **UTF-8** 2 `110xxxxx` `10xxxxxx` 3 `1110xxxx` `10xxxxxx` `10xxxxxx` 4 `11110xxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` **UTF-8000** 5 `111110xx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` 6 `1111110x` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` 7 `11111110` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` 8 `11111111` `100xxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` 9 `11111111` `1010xxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` 10 `11111111` `10110xxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` ... 22 `11111111` `10111111` `10111111` `10110xxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` `10xxxxxx` ... `10xxxxxx` ... 这里的示例 22 字节码元并非特殊情形。它只是一个很好的典型示例,展示了 UTF-8000 使用多个起始字节的能力。仅有两种特殊情况,均继承自 UTF-8:ASCII 保持原样,以及 2 字节 UTF-8 有 4 个强制内容位需检查超长编码,而所有更长的码元则为 5 个。 ## 结构剖析 以下是 TLDR (https://utf-8000.jb2170.com/#sec-tldr) 中示例 22 字节码元的结构剖析图。参见术语表 (https://utf-8000.jb2170.com/#sec-glossary) 了解术语定义的更多信息。 第四个字节令人兴奋!它既是一个续接字节,也是一个起始字节,是最后一个起始字节,包含内容位,且仅包含部分强制内容位,这些强制内容位横跨最后一个起始字节和第一个非起始字节。 UTF-8000 规范的主要贡献在于清晰地将 UTF-8 码元首字节的最高位划分为 **自同步位** 和 **起始位**,然后阐明如何在需要时将起始位跨续接字节分布,以实现任意大的码元。 ## 术语表 这些术语的排列顺序大致遵循首次需求的顺序,而非字母顺序,以方便阅读。定义中使用的术语带有下划线 (https://utf-8000.jb2170.com/#sec-glossary) 可点击超链接。 | 术语 | 定义 | | :--- | :--- | | **码点 (Codepoint)** | 一个非负整数,即无符号整数。 | | **码元 (Code Unit)** | 一个 UTF-8000 字节序列,用于编码单个**码点** (https://utf-8000.jb2170.com/#def-codepoint)。 | | **首字节 (First Byte)** | 一个 UTF-8000 **码元** (https://utf-8000.jb2170.com/#def-code-unit) 的起始字节,且唯一。**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 的**自同步前缀** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 对于 ASCII 是 `0`,对于多字节**码元** (https://utf-8000.jb2170.com/#def-code-unit) 是 `11`。此术语**并非**同义于**起始字节** (https://utf-8000.jb2170.com/#def-start-byte)。**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 必然是**起始字节** (https://utf-8000.jb2170.com/#def-start-byte),反之则不成立。因此,**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 有时也称为**首起始字节** (https://utf-8000.jb2170.com/#def-first-byte)。<br><br>有趣观察:由于自同步前缀 `0`,ASCII 字节的高十六进制半字节只能是 `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7` 之一。此术语因**自同步** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 而与**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte) 互斥。 | | **续接字节 (Continuation Byte)** | 多字节 UTF-8000 **码元** (https://utf-8000.jb2170.com/#def-code-unit) 中**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 之后的字节。**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte) 的自同步前缀是 `10`,这也称为**续接前缀位** (https://utf-8000.jb2170.com/#def-continuation-byte)。<br><br>有趣观察:由于自同步前缀 `10`,**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte) 的高十六进制半字节只能是 `8`, `9`, `A`, `B` 之一。此术语因**自同步** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 而与**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 互斥。 | | **自同步前缀 (Self-Synchronization Prefix)** | 每个 UTF-8000 字节的最高位,用于指示它是**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 还是**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte)。可能的**自同步前缀** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 构成一个前缀码树:<br>```<br>.----0 ASCII 的首字节<br>`----1---0 多字节 UTF-8000 的续接字节<br>`----1 多字节 UTF-8000 的首字节<br>```<br>UTF-8 中的这一巧妙架构片段被 UTF-8000 继承,提供了字节级的**自同步** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 属性:仅通过查看这些最高位,我们就能即时辨别正在查看的字节类型及其在码元中应属的位置。这在解码部分用 UTF-8000 编码的文件时最为有用。如果我们随机寻址到文件中的任意字节,我们可以明确地判断我们是处于**首字节** (https://utf-8000.jb2170.com/#def-first-byte)(由此可以立即开始解码新的**码元** (https://utf-8000.jb2170.com/#def-code-unit)),还是处于**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte)(由此需要向后寻址一点以找到下一个**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 才能开始解码)。我们也不需要处理寻址位置之前的任何字节来发现某些全局状态或寻址字节的上下文;**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 无论出现在何处,都始终明确无误地是**首字节** (https://utf-8000.jb2170.com/#def-first-byte),我们可以通过其自同步前缀为 `0` 或 `11` 来推断。<br><br>这不仅对随机访问有用,对错误恢复也有用。假设我们正在解码一个易出错的 UTF-8000 字节流,并且每当我们遇到错误(例如一个异常的 0xC0 字节)时,我们希望保持冷静并继续,而不是立即退出。我们可以输出 Unicode 替换字符 `U+FFFD` �,然后等待下一个**首字节** (https://utf-8000.jb2170.com/#def-first-byte),丢弃其间的任何内容。有关更通用的信息,请参阅关于自同步码 (https://en.wikipedia.org/wiki/Self-synchronizing_code) 的维基百科文章。<br><br>这些位以亮青色突出显示。 | | **起始字节 (Start Byte)** | 一个包含一个或多个**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 的字节。**起始字节** (https://utf-8000.jb2170.com/#def-start-byte) 在 UTF-8000 **码元** (https://utf-8000.jb2170.com/#def-code-unit) 的开头连续存在。UTF-8000 的强大之处在于我们可以有多个**起始字节** (https://utf-8000.jb2170.com/#def-start-byte),以实现任意**码元** (https://utf-8000.jb2170.com/#def-code-unit) 长度,从而编码任意大的**码点** (https://utf-8000.jb2170.com/#def-codepoint)。有时在讨论码元开头的字节时,将 ASCII 通俗地包含为**起始字节** (https://utf-8000.jb2170.com/#def-start-byte) 是合理的,尽管 ASCII 字节没有**起始位** (https://utf-8000.jb2170.com/#def-start-bits)。每个非 ASCII **码元** (https://utf-8000.jb2170.com/#def-code-unit) 至少有一个**起始字节** (https://utf-8000.jb2170.com/#def-start-byte)。第一个**起始字节** (https://utf-8000.jb2170.com/#def-start-byte) 是**首字节** (https://utf-8000.jb2170.com/#def-first-byte),其后是零个或多个也是**起始字节** (https://utf-8000.jb2170.com/#def-start-byte) 的**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte)。因此,由于一个 UTF-8000 **码元** (https://utf-8000.jb2170.com/#def-code-unit) 可以有多个**起始字节** (https://utf-8000.jb2170.com/#def-start-byte),此术语**并非**同义于**首字节** (https://utf-8000.jb2170.com/#def-first-byte)。在仅限于 UTF-8(不含 UTF-8000)的情况下,此术语*是*同义于**首字节** (https://utf-8000.jb2170.com/#def-first-byte)。这是因为 UTF-8 长度的**码元** (https://utf-8000.jb2170.com/#def-code-unit) 只需要一个**起始字节** (https://utf-8000.jb2170.com/#def-start-byte),无论是在当前 UTF-8 标准 (RFC 3629 (https://datatracker.ietf.org/doc/html/rfc3629) (2003)) 中使用最多 4 字节,还是在以前的标准 (RFC 2044 (https://datatracker.ietf.org/doc/html/rfc2044) (1996) 和 RFC 2279 (https://datatracker.ietf.org/doc/html/rfc2279) (1998)) 中使用最多 6 字节。 | | **起始位 (Start Bits)** | 多字节 UTF-8000 **码元** (https://utf-8000.jb2170.com/#def-code-unit) 的**起始字节** (https://utf-8000.jb2170.com/#def-start-byte) 中包含的一元编码位序列,用于指示**码元** (https://utf-8000.jb2170.com/#def-code-unit) 的字节长度。对于由 `n` 字节组成的**码元** (https://utf-8000.jb2170.com/#def-code-unit),**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 是 `n-2` 个 `1` 位,后跟一个终止 `0` 位。需明确,**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 包含这个终止零位。因此,**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 序列的长度为 `n-1`,形如 `111...10`。可能的**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 序列构成一个前缀码树:<br>```<br>.----0 两字节 UTF-8<br>`----1---0 三字节 UTF-8<br>`----1---0 四字节 UTF-8<br>`----1---0 五字节 UTF-8000<br>`----... n 字节 UTF-8000<br>```<br>对于 `n < 8` 的 `n` 字节**码元** (https://utf-8000.jb2170.com/#def-code-unit),**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 全部紧密地放在**首字节** (https://utf-8000.jb2170.com/#def-first-byte) 中。否则,它们会分布在所需的前几个字节上,填满未被**续接前缀位** (https://utf-8000.jb2170.com/#def-continuation-byte) 占用的空闲位。<br><br>这是 UTF-8 中另一个巧妙架构片段,被 UTF-8000 继承,提供了**自标点** (https://utf-8000.jb2170.com/#def-start-bits) 属性,也称为**前缀码**或**前缀无歧义码**:当解码多字节**码元** (https://utf-8000.jb2170.com/#def-code-unit) 时,一旦我们读取到**起始字节** (https://utf-8000.jb2170.com/#def-start-byte) 的末尾,即遇到终止 `0` 位,我们就确切知道该**码元** (https://utf-8000.jb2170.com/#def-code-unit) 期望包含多少字节。因此,除了错误之外,我们可以通过读取正好那么多字节来成功解码**码元** (https://utf-8000.jb2170.com/#def-code-unit),不多不少。这避免了更笨拙的可变长度编码的问题,其**码元** (https://utf-8000.jb2170.com/#def-code-unit) 本身不指示其长度:必须读取超过**码元** (https://utf-8000.jb2170.com/#def-code-unit) 最后一个字节,即读取下一个**码元** (https://utf-8000.jb2170.com/#def-code-unit) 的**首字节** (https://utf-8000.jb2170.com/#def-first-byte),才能知道当前**码元** (https://utf-8000.jb2170.com/#def-code-unit) 已结束。对于既没有**自同步** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 也没有**自标点** (https://utf-8000.jb2170.com/#def-start-bits) 的非常笨的编码,为了使随机访问成为可能,必须在**码元** (https://utf-8000.jb2170.com/#def-code-unit) 之间放置专用的辅助字节,如逗号字节,以能够分辨一个码元的结束和另一个的开始。<br><br>有关更通用的信息,请参阅关于前缀码 (https://en.wikipedia.org/wiki/Prefix_code) 和一元编码 (https://en.wikipedia.org/wiki/Unary_coding) 的维基百科文章。此术语与**内容位** (https://utf-8000.jb2170.com/#def-content-bits) 互斥。这些位以亮洋红色突出显示。 | | **内容字节 (Content Byte)** | 一个包含一个或多个**内容位** (https://utf-8000.jb2170.com/#def-content-bits) 的字节。一个字节是**内容字节** (https://utf-8000.jb2170.com/#def-content-byte) 并不意味着它是**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte)。例如,一个 3 字节**码元** (https://utf-8000.jb2170.com/#def-code-unit) 以 `1110xxxx` 开头,包含 4 个**内容位** (https://utf-8000.jb2170.com/#def-content-bits),它不是**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte)。一个字节是**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte) 并不意味着它是**内容字节** (https://utf-8000.jb2170.com/#def-content-byte)。例如,一个 22 字节**码元** (https://utf-8000.jb2170.com/#def-code-unit) 的第二个字节是 `10111111`,这是一个**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte),且没有**内容位** (https://utf-8000.jb2170.com/#def-content-bits)。 | | **内容位 (Content Bits)** | 在**码元** (https://utf-8000.jb2170.com/#def-code-unit) 中位于**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 之后直至**码元** (https://utf-8000.jb2170.com/#def-code-unit) 结尾的位序列,用于存储**码点** (https://utf-8000.jb2170.com/#def-codepoint) 的二进制位。例如,一个形如 `1110xxxx` `10xxxxxx` `10xxxxxx` 的 3 字节**码元** (https://utf-8000.jb2170.com/#def-code-unit) 有 16 个**内容位** (https://utf-8000.jb2170.com/#def-content-bits)。对于 ASCII,有 7 个**内容位** (https://utf-8000.jb2170.com/#def-content-bits)。这七个位 `xxxxxxx` 结合字节的最高位设置为自同步前缀 `0`,意味着 ASCII 被完美地包含在 UTF-8 中而不被改变。因此,ASCII **码元** (https://utf-8000.jb2170.com/#def-code-unit) 形如 `0xxxxxxx`。<br><br>否则,对于一个 `n` 字节**码元** (https://utf-8000.jb2170.com/#def-code-unit)(其中 `n > 1`),有 `5n+1` 个**内容位** (https://utf-8000.jb2170.com/#def-content-bits)。推导此公式如下:我们从 `n` 个空白字节开始,每个字节有 `8` 位。每个字节中 `2` 位被**自同步前缀** (https://utf-8000.jb2170.com/#def-self-synchronization-prefix) 占用。然后,另外 `n-1` 位被**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 占用。因此,剩余 `8n - 2n - (n-1) = 5n+1` 位用于**内容位** (https://utf-8000.jb2170.com/#def-content-bits)。<br><br>理解此公式中 `5` 的另一种方式是:通过附加另一个**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte),从 `n-1` 字节扩展到 `n` 字节。这样做,我们在**续接字节** (https://utf-8000.jb2170.com/#def-continuation-byte) 中获得 `6` 个空闲位,但我们因更长的**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 序列而损失 `1` 位,因此总体上我们获得 `6 - 1 = 5` 位用于**内容位** (https://utf-8000.jb2170.com/#def-content-bits)。此术语与**起始位** (https://utf-8000.jb2170.com/#def-start-bits) 互斥。 |

相似文章

超越困惑度:面向字节感知语言模型中的UTF-8有效性

arXiv cs.CL

本文研究了字节级语言模型中训练规模与UTF-8生成可靠性之间的关系,发现UTF-8有效性收敛的速度比困惑度大约慢一倍。作者引入了用于隔离结构有效性的评估协议,并表明可靠的UTF-8生成是一种需要单独评估的独特能力。

Unicode 的转写规则是图灵完备的

Hacker News Top

Unicode 的转写规则(UTS #35)通过编译2-标签系统被证明是图灵完备的,显示终止问题不可判定。这一结果影响了许多系统中使用的 ICU 库。

当编译器对 UTF-8 意见不一致时

Hacker News Top

深入探讨 utfcpp 库中 UTF-8 解码的优化,揭示 Clang 和 GCC 为 ASCII 快速路径生成不同的汇编代码,从而导致显著的性能差异。

Unicode 字符串的等价性很奇怪 (2016)

Lobsters Hottest

Unicode 字符串等价性很复杂,尤其是涉及校对规则时,会导致意外的结果,例如删除控制字符和非确定性分组。作者讨论了在数据库系统中正确实现 Unicode 支持所面临的挑战。