高 unicode 码点如何表示为两个码点?
Posted
技术标签:
【中文标题】高 unicode 码点如何表示为两个码点?【英文标题】:How is a high unicode codepoint expressed as two codepoints? 【发布时间】:2016-02-12 01:25:37 【问题描述】:我 seen 认为 >2 字节的 unicode 代码点(如 U+10000)可以写成一对,如 \uD800\uDC00
。它们似乎以轻咬 d
开头,但我注意到的仅此而已。
这个分裂动作叫什么?它是如何工作的?
【问题讨论】:
UTF 定义了代码点如何编码为代码单元,其大小可以是 7 位、8 位、16 位或 32 位,具体取决于 UTF。 UTF-8 使用 1、2、3 或 4 个 8 位代码单元对代码点进行编码,具体取决于代码点的值。 UTF-16 使用 1 个或 2 个 16 位代码单元对代码点进行编码,其中 2 个代码单元一起作用称为代理对。每个 UTF 都定义了自己的算法,用于将代码点转换为代码单元序列,反之亦然。阅读 UTF 规范。 简而言之,对于 UTF-16,如果代码点 > 0xFFFF,则从中减去 0x010000,剩下 20 位。它们被分成两半,其中高 10 位添加到 0xD800,低 10 位添加到 0xDC00。从而创建一个代理对。 Unicode 最初是 16 位标准,一直到第 3 版。当决定需要更多位时,预留了一组代码点来编码更高的代码点,以便围绕16 位版本在没有重大改造的情况下仍然可以“工作”。将代码点编码为代理对和 UTF-16 将代码点直接编码为 UTF-16。注意 UTF-8 用于支持编码为代理对的补充代码点,总共 6 个字节。这不再受支持。见 CESU-8,unicode.org/reports/tr26 @ShannonSeverance:您所指的“16 位版本”被称为 UCS-2,而不是 UTF-16。 UTF-16 向后兼容 UCS-2,但为编码不适合 UCS-2 的代码点添加了代理对。 @Clearquestionwithexamples:代理对是两个 16 位代码单元一起工作。您在问题中显示的这对使用转义序列来表示各个代码单元的数值。 【参考方案1】:UTF-8 意味着(用我自己的话)处理的最小原子是一个字节(代码单元是 1 字节长)。我不知道从历史上看是否,但至少从概念上讲,UCS-2 和 UCS-4 Unicode 编码是第一位的,而 UTF-8/UTF-16 似乎可以解决 UCS-* 的一些问题。
UCS-2 表示每个字符使用 2 个字节而不是 1 个字节。这是一个固定长度的编码。如您所说,UCS-2 保存每个代码点的字节串。问题是有些字符的代码点需要超过 2 个字节来存储它。因此,UCS-2 只能处理 Unicode 的一个子集(当然范围是 U+0000 到 U+FFFF)。
UCS-4 对每个字符使用 4 个字节,显然它足以存储任何 Unicode 代码点的位串(Unicode 范围从 U+000000 到 U+10FFFF)。
UCS-4 的问题在于 2 字节范围之外的字符非常非常少见,使用 UCS-4 编码的任何文本都会浪费太多空间。因此,使用 UCS-2 是一种更好的方法,除非您需要 2 字节范围之外的字符。
但同样,英文文本、源代码文件等主要使用 ASCII 字符,UCS-2 也有同样的问题:为主要使用 ASCII 字符的文本浪费了太多空间(太多无用的零)。
这就是 UTF-8 的作用。 ASCII 范围内的字符按原样保存在 UTF-8 文本中。它只需要每个字符的代码点/ASCII 值的位串。因此,如果 UTF-8 编码的文本仅使用 ASCII 字符,则它与任何其他 Latin1 编码都无法区分。不支持 UTF-8 的客户端可以仅使用 ASCII 字符处理 UTF-8 文本,因为它们看起来相同。这是一种向后兼容的编码。
从那时起(ASCII 范围之外的 Unicode 字符),UTF-8 文本使用两个、三个或四个字节来保存代码点,具体取决于字符。
我不知道确切的方法,但是使用已知的位前缀将 bitstring 拆分为两个、三个或四个字节,以了解用于保存代码点的字节数。如果一个字节以 0 开头,则表示该字符是 ASCII 并且仅使用 1 个字节(ASCII 范围为 7 位长)。如果它以 1 开头,则根据接下来的位使用两个、三个或四个字节对字符进行编码。
UTF-8 的问题在于它需要太多的处理(它必须检查每个字符的第一位才能知道它的长度),特别是在文本不是英文的情况下。例如,用希腊语编写的文本将主要使用两个字节的字符。
UTF-16 使用两字节代码单元来解决非 ASCII 文本的问题。这意味着处理的原子是 16 位字。如果字符编码不适合两字节代码单元,则它使用 2 个代码单元(四个字节)对字符进行编码。这对两个代码单元称为代理对。我认为仅使用 2 字节范围内的字符的 UTF-16 文本等同于使用 UCS-2 的相同文本。
UTF-32 反过来使用 4 字节的代码单元,就像 UCS-4 一样。不过我不知道它们之间的区别。
【讨论】:
我相信您说过您对可变宽度编码的工作原理感到困惑。我发现 this 很有帮助。 UTF-8 最多需要 4 个字节来存储 21 位代码点,因为一个代码单元存储 6 位数据 UCS-4 最大的问题不是内存要求,而是主要平台标准化其 Unicode 实现时 Unicode 不需要那么多位。 UTF-8 优雅地解决的另一个问题是,您可以从每个单独的字节中分辨出它在多字节序列中的位置;使用传统的多字节编码,您可能会失控和/或必须扫描几个周围的字节以找出如何解释当前字节。【参考方案2】:填写你困惑的完整图片格式如下:
参考我从 cmets 学到的东西...
U+10000
是 Unicode code point(映射到字符的十六进制整数)。
Unicode 是代码点到字符的一对一映射。
从0xD800
到0xDFFF
的代码点范围保留给UTF-161 (Unicode vs UTF) 代理单元(见下文)。
\uD800\uDC00
2 是两个这样的代理单元,称为 surrogate pair。 (代理单元是代理对中的代码单元。)
抽象表示: 代码点(抽象字符)-->
Code unit(抽象 UTF-16)-->
代码单元(UTF-16 编码字节)-->
解释 UTF-16
实际使用示例: 输入数据是字节,可以用第二种编码包装,如用于 html 实体的 ASCII 和 unicode 转义,或解析器处理的任何 -->
编码解释;通过方案-->
字体字形-->
屏幕上的字符映射到代码点
How surrogate pairs work
代理对优势:
-
只有高单位和低单位。一个高点必须跟着一个低点。没有令人困惑的高低单位。
UTF-16 可以将 2 个字节用于前 63487 个代码点,因为代理项不会被误认为代码点。
2048 个代码点的范围是
(2048/2)**2
以产生 1048576 个代码点的范围。
处理是在less frequently 使用的字符上完成的。
1 UTF-16 是唯一一个使用代理对的 UTF。2 这被格式化为 unicode escape sequence。
描述字符编码的图形:
继续阅读:
How does UTF-8 "variable-width encoding" work? Unicode, UTF, ASCII, ANSI format differences Code point【讨论】:
请注意,代理对实际上不是两个字符,除非它被错误解码;正确解码后,它是 SMP 中的单个字符。以上是关于高 unicode 码点如何表示为两个码点?的主要内容,如果未能解决你的问题,请参考以下文章