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

问题描述

根据Unicode specification

D91 UTF-16 编码形式:分配每个字符的 Unicode 编码形式 U+0000..U+D7FF 和 U+E000..U+FFFF 范围内的 Unicode 标量值 到具有相同数值的单个无符号 16 位代码单元 Unicode 标量值,并且 分配每个 Unicode 标量值 在 U+10000..U+10FFFF 到代理对的范围内

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

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

D76 Unicode 标量值: 除高代理外的任何 Unicode 代码点 和低代理代码点。

等等... 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 范围)。当互操作者在计算机内存中遇到 D800..DBFF(高代理区)值时,它知道这不是隐含的“成熟”代码点(不是标量值 > 在规范方面),它应该再读取 16 位以从 DC00..DFFF 范围(低代理区域)中获取值,并最终得出 U+10000..U+10FFF 中的哪一个代码点是用这 4 个字节编码的(使用这个 Surrogate Pair)。请注意,这种方案可以对 1 024 * 1 024 = 1 048 576 个代码点进行编码(这与我们需要的数量完全相同)。
  • 由于 Unicode Codespace 被定义为从 0 到 10FFFF 的整数范围,我们不得不引入代理代码(不是代码单位) - U+D800..U+DBFF 范围(因为我们不能从 unicode 代码空间中排除这个范围)。鉴于代理代码点是为 UTF-16 中的代理代码单元指定的(参见 C1、D74),这些代码点可以看作是 UTF-16 遗物。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...