解释
Surrogate Pairs 主要是针对增补字符,此时一个16位的编码(2个Byte的UTF-16)已经无法表示,所以就扩展成需要两个16位的编码单元。也就是说,在范围U+10000到U+10FFFF间的编码则使用一对16位编码单元表示,称作代理对(surrogate pair)。
在BMP内的字符,仍然按照UTF-16的编码规则,使用两个字符来表示。 (注:BMP内的字符编码,不包含从U+D800到U+DFFF的预留码位。这些预留码位就恰好用于扩展字符编码)
增补字符的编码值已经超过了BMP的编码范围,需要使用一对UTF-16字符来表示一个字符。把Unicode编码记作U。编码规则如下:
- 如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数。
- 如果U≥0x10000,
- 先计算U’=U-0x10000,
- 然后将U’写成二进制形式:yyyy yyyy yyxx xxxx xxxx,(注意这里共计20位)
- U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。
这两个字符就称为surrogate pair(代理对)。第一个代理字符为16位编码,范围为U+D800到U+DBFF,第二个代理字符也是一个16位编码,范围为U+DC00 to U+DFFF。
Wikipedia Examples
在wikipedia上有一个计算的例子,原则上和上面是一样的,表述略有不同:
把 U+10437 (?) 转换成 UTF-16:
- 0x10437- 0x100000 = 0x0437.
- high surrogate: 0x0437右移10位 (相当于除以0x400,也相当于扩展成20位之后,取左边的高10位), 然后加上 0xD800,得到:0x0001 + 0xD800 = 0xD801.
- low surrogate, 取低10位(相当于对0x400取余), 然后加上0xDC00, 得到:0x0037 + 0xDC00 = 0xDC37.
从 UTF-16 解码 U+10437 (?) :
- 取high surrogate, 0xD801 - 0xD800(等价于:0xD801&0x3FF), 结果再乘以 0x400, 得到:(0xD801-0xD800)×0x400=0x0001×0x400=0x0400
- 取low surrogate,0xDC37-0xDC00(等价于:0xDC37&0x3FF), 得到:(0xDC37-0xDC00) = 0x0037.
- 把上述两个结果相加,0x0400+ 0x0037 =0x0437, 最后加上0x10000得到0x10437,这个就是最终的UTF-32 code point, 0x10437.
The following table summarizes this conversion, as well as others. The colors indicate how bits from the code point are distributed among the UTF-16 bytes. Additional bits added by the UTF-16 encoding process are shown in black.
Character | Binary code point | Binary UTF-16 | UTF-16 hex code units | UTF-16BE hex bytes | UTF-16LE hex bytes | |
$ | | | | | | |
€ | | | | | | |
? | | | | | | |
? | | | | | | |
应用举例:
python的源码(UnicodeObject.h)中有这么几个定义,
1。用来判断是否有UTF-16代理surrogate,
#define Py_UNICODE_IS_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDFFF)
#define Py_UNICODE_IS_HIGH_SURROGATE(ch) (0xD800 <= (ch) && (ch) <= 0xDBFF)
#define Py_UNICODE_IS_LOW_SURROGATE(ch) (0xDC00 <= (ch) && (ch) <= 0xDFFF)
2。从UTF16解码的过程如下,
#define Py_UNICODE_JOIN_SURROGATES(high, low) \
(((((Py_UCS4)(high) & 0x03FF) << 10) | \
((Py_UCS4)(low) & 0x03FF)) + 0x10000)
注:Py_UCS4定义:typedef uint32_t Py_UCS4;
3。取得high surrogate和low surrogate的宏代码如下
/* high surrogate = top 10 bits added to D800 */
#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 - (0x10000 >> 10) + ((ch) >> 10))
/* low surrogate = bottom 10 bits added to DC00 */
#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 + ((ch) & 0x3FF))
【1】 https://en.wikipedia.org/wiki/UTF-16