天天看點

Unicode:Surrogate Pairs UTF-16中用于擴充字元

解釋

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

$

U+0024

0000 0000 0010 0100

0000 0000 0010 0100

0024

00 24

24 00

U+20AC

0010 0000 1010 1100

0010 0000 1010 1100

20AC

20 AC

AC 20

?

U+10437

0001 0000 0100 0011 0111

1101 1000 0000 0001 1101 1100 0011 0111

D801 DC37

D8 01 DC 37

01 D8 37 DC

?

U+24B62

0010 0100 1011 0110 0010

1101 1000 0101 0010 1101 1111 0110 0010

D852 DF62

D8 52 DF 62

52 D8 62 DF

應用舉例:

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的宏代碼如下

#define Py_UNICODE_HIGH_SURROGATE(ch) (0xD800 - (0x10000 >> 10) + ((ch) >> 10))

#define Py_UNICODE_LOW_SURROGATE(ch) (0xDC00 + ((ch) & 0x3FF))

【1】 https://en.wikipedia.org/wiki/UTF-16

繼續閱讀