UTF-16的替代方案
我认为你正在提出一种使用16位代码单元的替代格式,类似于UTF-8编码方案 - 让我们将其指定为UTF-EMF-16。
在您的UTF-EMF-16方案中,从U+0000到U+7FFF的码点将被编码为具有MSB(最高有效位)始终为零的单个16位单位。然后,您将保留16位单位,其中2个最高有效位设置为10
作为“连续单元”,带有14位有效数据。然后,您将使用三个最高有效位设置为110
的16位单位对U+8000到U+10FFFF(当前最大的Unicode码点)进行编码,并具有多达13位有效数据。使用Unicode的当前定义(U+0000 .. U+10FFFF),您永远不需要设置超过13位中的7位。
U+0000 .. U+7FFF — One 16-bit unit: values 0x0000 .. 0x7FFF
U+8000 .. U+10FFF — Two 16-bit units:
1. First unit 0xC000 .. 0xC043
2. Second unit 0x8000 .. 0xBFFF
对于您提供的示例代码点,U+1F683(二进制:1 1111 0110 0100 0011):
First unit: 1100 0000 0000 0111 = 0xC007
Second unit: 1011 0110 0100 0011 = 0xB643
第二个单元与你的示例不同,它将最高有效位从你的示例中的
01
反转为我的
10
。
为什么UTF-16没有使用这样的方案?
这样的方案可以运作。它是明确的。它可以容纳比Unicode当前允许的更多的字符。UTF-8可以修改为UTF-EMF-8,以处理相同的扩展范围,其中一些字符需要5个字节而不是当前最大的4个字节。UTF-EMF-8带有5个字节可编码高达26位;UTF-EMF-16可以编码27位,但应限制为26位(约6400万个代码点,而不是略多于100万个)。那么,为什么它或类似的东西没有被采用呢?
答案是非常普遍的 - 历史(加上向后兼容性)。
当Unicode首次定义时,人们希望或认为一个16位代码集足够了。使用16位值开发了UCS2编码,并赋予了许多值在0x8000 .. 0xFFFF范围内的含义。例如,U+FEFF是字节顺序标记。
当Unicode方案必须扩展以使Unicode成为更大的代码集时,许多具有最高有效位中的
10
和
110
位模式的定义字符,因此向后兼容性意味着不能在不破坏与UCS2的兼容性的情况下将上述UTF-EMF-16方案用于UTF-16,这将是一个严重的问题。
因此,标准化机构选择了一种替代方案,其中有高代理项和低代理项。
0xD800 .. 0xDBFF High surrogates (most signicant bits of 21-bit value)
0xDC00 .. 0xDFFF Low surrogates (less significant bits of 21-bit value)
低代理项范围提供了10位数据的存储空间——前缀
1101 11
使用16位中的6位。高代理项范围也提供了10位数据的存储空间——前缀
1101 10
同样使用16位中的6位。但由于BMP(基本多语言平面——U+0000..U+FFFF)不需要用两个16位单元进行编码,UTF-16编码从高阶数据中减去
1
,因此可以用来编码U+10000..U+10FFFF。(请注意,尽管Unicode是一个21位编码,但并非所有21位(无符号)数字都是有效的Unicode代码点。值从0x110000..0x1FFFFF是21位数字,但不属于Unicode。)
来自Unicode
FAQ - UTF-8、UTF-16、UTF-32和BOM:
Q: What’s the algorithm to convert from UTF-16 to character codes?
A: The Unicode Standard used to contain a short algorithm, now there is just a bit distribution table. Here are three short code snippets that translate the information from the bit distribution table into C code that will convert to and from UTF-16.
Using the following type definitions
typedef unsigned int16 UTF16
typedef unsigned int32 UTF32
the first snippet calculates the high (or leading) surrogate from a character code C.
const UTF16 HI_SURROGATE_START = 0xD800
UTF16 X = (UTF16) C
UTF32 U = (C >> 16) & ((1 << 5) - 1)
UTF16 W = (UTF16) U - 1
UTF16 HiSurrogate = HI_SURROGATE_START | (W << 6) | X >> 10
where X, U and W correspond to the labels used in Table 3-5 UTF-16 Bit Distribution. The next snippet does the same for the low surrogate.
const UTF16 LO_SURROGATE_START = 0xDC00
UTF16 X = (UTF16) C
UTF16 LoSurrogate = (UTF16) (LO_SURROGATE_START | X & ((1 << 10) - 1))
Finally, the reverse, where hi and lo are the high and low surrogate, and C the resulting character
UTF32 X = (hi & ((1 << 6) -1)) << 10 | lo & ((1 << 10) -1);
UTF32 W = (hi >> 6) & ((1 << 5) - 1);
UTF32 U = W + 1;
UTF32 C = U << 16 | X;
A caller would need to ensure that C, hi, and lo are in the appropriate ranges. [
110110 0000111101
和11011 11001000011
。 - Mr Lister