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

4
根据Unicode规范,UTF-16编码形式将U+0000..U+D7FF和U+E000..U+FFFF范围内的每个Unicode标量值分配给一个具有相同数值的无符号16位代码单元,并将U+10000..U+10FFFF范围内的每个Unicode标量值分配给代理对。术语“标量值”是指Unicode代码点,这是一系列抽象概念,必须通过不同的编码形式(UTF-16等)进行编码成特定的字节序列。因此,似乎这段摘录的要点在于,并非所有代码点都可以容纳在一个UTF-16代码单元(两个字节)中,其中一些应该被编码为一对代码单元 - 4个字节(称为“代理对”)。然而,“标量值”这个术语的定义如下:任何Unicode代码点,除了高代理项和低代理项代码点。

等一下... Unicode 有代理码点吗?当UTF-16可以使用4个字节来表示标量值时,这是什么原因呢?有人能解释一下这种理论基础以及UTF-16如何使用这些代理码点吗?

2个回答

3

2
仅为了最终澄清。
  • UTF-16使用16位(2字节)代码单元。这意味着该编码格式将代码点(应以某种方式在计算机内存中表示的抽象概念)通常编码为16位(因此解释器可能会一次读取两个字节的数据)。
  • UTF-16做得很简单:例如,U+000E代码点将被编码为0x000EU+000F将被编码为0x000F,依此类推。
  • 问题在于16位只能涵盖范围不足以容纳所有Unicode代码点(0x0000 - 0xFFFF范围仅允许65,536个可能值)。对于超出这些边界的代码点,我们可以使用两个16位字(4个字节),但是这种方法导致无法解码某些值。例如,如果我们将U+10000代码点编码为0x00010000,那么解释器应该如何解码这样的表示形式:作为两个连续的不同代码点U+0001U+0000,还是作为单个代码点U+10000
  • Unicode规范决定了更好的方法。如果需要编码U+10000 - U+10FFFF范围(顺便说一下,这里有1,048,576个代码点),那么我们应该首先从一个字节范围中分离出1,024 + 1,024 = 2,048个值(规范选择了0xD800 - 0xDFFF用于这些目的)。当解释器遇到0xD800 - 0xDBFF值时,它知道这里没有隐含的“完整”的代码点(根据规范的术语,没有标量值),然后它应该读取另外16位以获取0xDC00 - 0xDFFF范围的值,并最终确定使用这4个字节编码了哪个U+10000 - U+10FFF代码点。请注意,此方案可以编码1,024 * 1,024 = 1,048,576个代码点(这正是我们需要的数字)。
  • Unicode规范只是将此整数范围包含在其Unicode代码空间中,该空间是从U+00000x10FFFF的代码点空间。然后U+D800 - U+DFFF子空间称为高代理区域,而U+DC00 - U+DFFF则在其中称为低代理区域。由于这些代码点的值与UTF-16代码单元(代码点的特定表示)的值相匹配,因此可以将此包含视为UTF-16遗物:
高代理项和低代理项代码点是为了UTF-16字符编码形式中的代理项编码单元而指定的。它们没有分配给任何抽象字符。[spec]

你最后一段中的“Then the U+D800 - U+DFFF subspace”似乎有一个重要的打字错误。应该是“U+DBFF”,如此处所定义(链接:https://www.unicode.org/charts/PDF/UD800.pdf)。 - undefined
@triplee,我不明白这个问题:“到底翻译员应该如何解码这样的表达方式……”你能否再详细解释一下? - undefined
我猜他们的意思是,“在纯16位编码中,无法用超过16位来表示一个码点,因为这样你就无法确定四个字节是表示一个码点还是两个不同的码点。”这就是为什么需要引入代理项的原因,作为扩展编码的一种方式,使其不再纯粹是一个16位编码,而是具有表示超过16位的序列的明确表示。(纯16位编码仍然存在,被称为UCS-2。显然,它无法表示BMP之外的码点。) - undefined
@BasilBourque 我同意你的分析,足够让我纠正了明显的打字错误。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接