出處:https://www.cnblogs.com/luizyao/
版權:本文版權歸作者所有
轉載:歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出
Unicode
在百度百科上,對Unicode的介紹是這樣的:
“ Unicode(統一碼、萬國碼、單一碼)是計算機科學領域里的一項業界標准,包括字符集、編碼方案等。Unicode 是為了解決傳統的字符編碼方案的局限而產生的,它為每種語言中的每個字符設定了統一並且唯一的二進制編碼,以滿足跨語言、跨平台進行文本轉換、處理的要求。”
Unicode標准為每一個字符提供一個唯一的數字,而不用區分平台、語言等因素。
The Unicode Standard provides a unique number for every character, no matter what platform, device, application or language.
Unicode源於一個很簡單的想法:將全世界所有的字符包含在一個集合里,計算機只要支持這一個字符集,就能顯示所有的字符,再也不會有亂碼了。
它從0開始,為每個符號指定一個編號,這叫做"碼位"(code point)(字符碼)。比如,碼位U+0639
表示阿拉伯字母Ain
,碼位U+0041
表示英語的大寫字母A
,碼位U+4E25
表示漢字嚴
。
目前,Unicode從7.0版開始,幾乎每年一個新版本(Unicode 12.1.0 2019年5月7號)。
基本概念
在開始學習之前,我們需要先了解本文所涉及到的一些基本概念。
抽象字符(Abstract character):用於組織、控制或者表示文本數據的信息單元。
- 抽象字符沒有具體的形式,不應與圖像字符(glyph)混淆。
- 抽象字符不一定對應於人們所認知的“字”,不應與字素(grapheme)混淆。
- 不能被Unicode標准直接編碼的抽象字符通常可以通過組合字符序列來表示。
抽象字符序列(Abstract character sequence):一個或多個抽象字符的有序序列。
Unicode編碼空間(Unicode codespace):十六進制0x0~0x10FFFF之間的整數。
碼位(Code point):Unicode編碼空間中的任意值。
編碼字符(Coded character):當抽象字符被映射或者分配到編碼空間中特定的碼位時,它就被稱為編碼字符。
碼位
碼位是Unicode標准中很重要的一個概念。目前它的取值范圍是十六進制的0x0~0x10FFFF
,換算成十進制是0~1114111
,共計1114112
個。
需要注意的是,一個單一的抽象字符可能對應一個以上的碼位。例如,Ω
既可以表示大寫的希臘字母Omega,碼位是U+03A9
,也可以表示物理學中的歐姆符號,碼位是U+2126
。
>>> '\u03a9'
'Ω'
>>> '\u2126'
'Ω'
單個抽象字符也可以由一系列碼位的序列來表示。例如,é
的碼位是U+00E9
,它也可以由小寫字母e
(碼位為U+0065
)'
(Combining Acute Accent)(碼位為U+0301
)組合而成。
>>> '\u00e9'
'é'
>>> '\u0065\u0301'
'é'
在Unicode標准中,碼位的表示方法通常是使用它們的十六進制,並加上U+
前綴。
碼位的類型
碼位的分類方法多種多樣。我們通過下表來闡明Unicode標准使用的七種類型和一些術語。
基本類型 | 簡要描述 | 是否分配給 抽象字符 |
碼位范圍 |
---|---|---|---|
圖形(Graphic) | 字母、標記、數字、標點符號、符號和空格 | 是 | |
格式(Format) | 不可見但是影響相鄰字符。包括行、段落分割符 | 是 | |
控制(Control) | Unicode標准以外的協議或標准定義的用法 | 是 | U+0000~U+001F,U+007F,U+0080~U+009F,共計65個 |
私用(Private-use) | Unicode標准以外的私有協議定義的用法 | 是 | |
代理 (Surrogate) | 永久預留給UTF-16編碼方案 | 不允許分配 | U+D800~U+DFFF,共計2048個 |
非字符(Noncharacter) | 永久預留給內部使用 | 否 | U+FDD0~U+FDEF,所有以FFFE或者FFFF結尾的碼位,共計66個 |
保留(Reserved) | 預留給將來使用 | 否 |
我們需要格外注意代理(Surrogate)類型,理解他有助於我們學習UTF-16。它總共包含2048個碼位,碼位空間為U+D800~U+DFFF。它由引發出兩個新的概念:
高位代理(High-Surrogate):U+D800~U+DBFF范圍內的碼位,共計1024個。
低位代理(Low-Surrogate):U+DC00~U+DFFF范圍內的碼位,共計1024個。
關於它們更多的內容,稍后結合UTF-16再討論。
編碼方案
在介紹具體的編碼方案之前,我們先明確一些新的基本概念。
Unicode標量值(Unicode scalar value):除去高位代理和低位代理之外,所有的Unicode碼位,也就是U+0000~U+D7FF和U+E000~U+10FFFF范圍內的碼位。
編碼單元(Code unit):最小的比特位組合,表示用於交換或處理的編碼文本單元。Unicode標准中定義,UTF-8使用8比特的編碼單元,UTF-16使用16比特的編碼單元,UTF-32使用32比特的編碼單元。
編碼單元序列(Code unit sequence):一個或多個編碼單元的有序序列。
UTF-32
UTF-32將每個Unicode標量值映射成一個無符號的32比特的編碼單元,數值與Unicode標量值相同,這是一種定長的編碼方案。
注意,UTF-32無法編碼U+D800~U+DFFF之間的碼位,因為它們不屬於Unicode標量值。
>>> '\ud800'.encode('utf32')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-32' codec can't encode character '\ud800' in position 0: surrogates not allowed
UTF-16
UTF-16將Unicode標量值中U+0000~U+D7FF
和U+E000~U+FFFF
范圍內的碼位映射成一個無符號的16比特的編碼單元,數值與Unicode標量值相同。將U+10000~U+10FFFF
范圍內的碼位映射成一個代理對,所謂的代理對就是上文提到的高位代理和低位代理。UTF-16是一種定長和變長兼顧的編碼方案。
UTF-16編碼以16位無符號整數為單位。我們把Unicode編碼記作U。編碼規則如下(百度百科):
- 如果
U<0x10000
,U的UTF-16編碼就是U對應的16位無符號整數(為書寫簡便,下文將16位無符號整數記作WORD)。 - 如果
U≥0x10000
,我們先計算U'=U-0x10000
,然后將U'
寫成二進制形式:0000 yyyy yyyy yyxx xxxx xxxx
(前四位0舍棄),U的UTF-16編碼(二進制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx
。
Unicode標量值 | UTF-16 |
---|---|
U<0x10000 | xxxx xxxx xxxx xxxx |
U≥0x10000 | 1101 10yy yyyy yyyy 1101 11xx xxxx xxxx |
xxxx xxxx xxxx xxxx | xxxx xxxx xxxx xxxx |
000u uuuu xxxx xxxx xxxx xxxx | 1101 10ww wwxx xxxx 1101 11xx xxxx xxxx |
其中, U'=U-0x10000, 再將U'拆分
其中, wwww = uuuuu - 1
以字符𐌂
(Old Italic Letter Ke)為例,它的碼位是U+10302
,二進制表示是0000 0001 0000 0011 0000 0010
,減去U+10000
(二進制為0000 0001 0000 0000 0000 0000
),得到0000 0000 0000 0011 0000 0010
(前四位0舍棄)。從右到左填充進模版,得到1101 1000 0000 0000 1101 1111 0000 0010
,對應的十六進制是D800 DF02
。
U+10302 = 0000 0001 0000 0011 0000 0010
U+10302 - U+10000 = 0000 0001 0000 0011 0000 0010
- 0000 0001 0000 0000 0000 0000
= 0000 0000 0000 0011 0000 0010
UTF-16 = 1101 1000 0000 0000 1101 1111 0000 0010
>>> '\U00010302'.encode('utf-16be') #'𐌂'.encode('utf-16be')
b'\xd8\x00\xdf\x02'
UTF-8
UTF-8將每個Unicode標量值映射成一到四個無符號的8比特的編碼單元,這是一種變長的編碼方案。
下表闡明了UTF-8的編碼方式。
Unicode標量值 | 第一個字節 | 第二個字節 | 第三個字節 | 第四個字節 |
---|---|---|---|---|
00000000 0xxxxxxx | 0xxxxxxx | |||
00000yyy yyxxxxxx | 110yyyyy | 10xxxxxx | ||
zzzzyyyy yyxxxxxx | 1110zzzz | 10yyyyyy | 10xxxxxx | |
000uuuuu zzzzyyyy yyxxxxxx | 11110uuu | 10uuzzzz | 10yyyyyy | 10xxxxxx |
仍然以字符𐌂
(Old Italic Letter Ke)為例,它的碼位是U+10302
,二進制表示是00000001 00000011 00000010
,套用表中的模式,得到 11110000 10010000 10001100 10000010
,對應的十六進制是F090 8C82。
00000001 00000011 00000010
000uuuuu zzzzyyyy yyxxxxxx
11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
11110000 10010000 10001100 10000010
>>> '\U00010302'.encode('utf-8') #'𐌂'.encode('utf-8')
b'\xf0\x90\x8c\x82'
下表闡明了UTF-8的所有有效編碼范圍。
Unicode標量值范圍 | 第一個字節 | 第二個字節 | 第三個字節 | 第四個字節 |
---|---|---|---|---|
U+0000 ~ U+007F | 00 ~ 7F | |||
U+0080 ~ U+07FF | C2 ~ DF | 80 ~ BF | ||
U+0800 ~ U+0FFF | E0 A0 ~ BF | 80 ~ BF | ||
U+1000 ~ U+CFFF | E1 ~ EC | 80 ~ BF | 80 ~ BF | |
U+D000 ~ U+D7FF | ED | 80 ~ 9F | 80 ~ BF | |
U+E000 ~ U+FFFF | EE ~ EF | 80 ~ BF | 80 ~ BF | |
U+10000 ~ U+3FFFF | F0 90 ~ BF | 80 ~ BF | 80 ~ BF | 80 ~ BF |
U+40000 ~ U+FFFFF | F1 ~ F3 | 80 ~ BF | 80 ~ BF | 80 ~ BF |
U+100000 ~ U+10FFFF | F4 80 ~ 8F | 80 ~ BF | 80 ~ BF | 80 ~ BF |
參考資料
- UnicodeStandard-12.0:https://www.unicode.org/versions/Unicode12.1.0/