UTF-16 编码如何使用代理代码点?

How UTF-16 encoding uses surrogate code points?

中照Unicode specification

D91 UTF-16 encoding form: The Unicode encoding form that assigns each Unicode scalar value in the ranges U+0000..U+D7FF and U+E000..U+FFFF to a single unsigned 16-bit code unit with the same numeric value as the Unicode scalar value, and that assigns each Unicode scalar value in the range U+10000..U+10FFFF to a surrogate pair.

术语“标量值”是指unicode代码点,即抽象概念的范围,必须通过不同的编码形式(UTF-16等)编码成特定的字节序列。所以这个摘录的要点似乎是考虑到并非所有代码点都可以容纳在一个 UTF-16 代码单元(两个字节)中,有些代码点应该编码成一对代码单元 - 4 个字节(称为“代理对").

然而,术语“标量值”的定义如下:

D76 Unicode scalar value: Any Unicode code point except high-surrogate and low-surrogate code points.

等等...Unicode 是否有代理代码?为什么UTF-16可以用4个字节来表示标量点呢?任何人都可以解释基本原理以及 UTF-16 如何使用此代码点吗?

是的,Unicode 为代理代码点保留范围:

Unicode 保留了这些范围,因为这些 16 位值用于代理项对,不能为它们分配其他符号。代理项对是两个 16 位值,它们对 U+FFFF 以上的代码点进行编码,但不适合单个 16 位值。

为了最终的澄清。

  • UTF-16 使用 16 位(2 字节)代码单元。这意味着这种编码格式通常将代码点(=抽象思想应该以某种方式在计算机内存中表示)编码为 16 位(因此据称解释器一次读取数据为两个字节)。
  • UTF-16 尽最大努力非常简单:U+000E 代码点将编码为 000E,U+000F 编码为 000F,依此类推。
  • 问题是 16 位只能提供不足以容纳所有 unicode 代码点的范围(0000..FFFF 只允许 65 536 个可能的值)。对于超出这个范围的代码点,我们可能会使用两个 16 位字(4 个字节)(实际上,我的误解是为什么 UTF-16 不这样做)。然而,这种方法导致无法解码某些值。例如,如果我们将 U+10000 代码点编码为 0001 0000(十六进制表示法),那么解释器到底应该如何解码这样的表示:作为两个后续代码点 U+0001 和 U+0000 还是作为单个 U+10000?
  • Unicode 规范倾向于更好的方式。如果需要对范围 U+10000..U+10FFF(1 048 576 个代码点)进行编码,那么我们应该将 1 024 + 1 024 = 2 048 个值与可以用 16 位编码的值分开(规范为此选择了 D800..DFFF 系列)。当一个 interpeter 在计算机内存中遇到 D800..DBFF(High Surrogate Area)值时,它知道它不是隐含的“完全成熟”代码点(不是 根据规范的标量值)并且它应该读取另外 16 位以从 DC00..DFFF 范围(低代理区域)中获取值并最终得出哪个U+10000..U+10FFF 代码点是用这 4 个字节编码的(使用这个 代理对 )。请注意,这种方案可以编码 1 024 * 1 024 = 1 048 576 个代码点(这与我们需要的数量完全相同)。
  • 由于Unicode Codespace定义为0到10FFFF的整数范围,我们不得不引入surrogate code的概念points(不是代码 units)- U+D800..U+DBFF 范围(因为我们不能从 unicode 代码空间中排除这个范围)。鉴于代理代码点是为 UTF-16 中的代理代码单元指定的(请参阅 C1、D74),这些代码点可以看作是 UTF-16 遗留物。