Unicode詳解


轉自 Unicode標准以及其常見的編碼方案

作者:luizyao
出處: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+D7FFU+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

參考資料

  1. UnicodeStandard-12.0:https://www.unicode.org/versions/Unicode12.1.0/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM