這篇文章將介紹Unicode編碼的相關知識以及Python中Unicode編碼的相關內容。
為了講清楚這個問題,我們從計算機的字節及字符編碼開始說起。
字節(Byte)是計算機信息技術中用于計量存儲容量的一種單位,通常情況下,一個字節等于8位(bit),1位可以表示為二進制中的0或1。
在很多計算機語言中,字節(Byte)也是一種數據類型,用于存儲字符。
在不同的字符編碼方式中,一個字符占用的字節數量可能不同。如在ASCII編碼方式下,用一個字節來存儲1個字符。
一個字節共8位,對應的無符號二進制數可以有256種(即28種)情形(0~255,最大數:28-1),如果用一個二進制數表示一個字符的話,那么最多可以表示256個不同字符。
為了便于在計算機中進行存儲和傳遞信息,在計算機技術中,將每個字符(包括控制字符,如回車、換行等)都分配唯一一個整型數字與其對應。如ASCII(American Standard Code for Information Interchange,美國信息交換標準碼)使用8位二進制數對字符(包括字母、數字、標點符號、控制字符及其它符號)進行編碼。因為八位的二進制數可以有256種數位(0和1)組合,最多能對256個字符進行編碼,這種情況下對于處理英文信息是完全夠用的,但是隨著計算機在全世界的普及使用,這種編碼方式已不足來處理更多的字符信息了,如我們常用的基本漢字就有三千多個,而ASCII編碼方式最多能為256個字符編碼,顯然這種編碼方式遠遠不夠用的,因此,我國隨后推出了漢字區位編碼方式,GB2312,GBK以及為處理繁體字設計的Big5等。
不同的編碼方式可能存在著沖突,即某一個編碼在不同的編碼方式中表示不同的字符,這為信息交換又帶來了困難,因此后來人們設計了能夠全球統一使用的Unicode編碼方式。
Unicode一般稱統一碼,現已成為計算機領域的業界標準,它為每種語言的每個字符或符號分配了統一且唯一的二進制碼,以滿足跨語言、跨平臺進行文本轉換和處理的要求(來自百度百科)。
Unicode為每個字符或符號分配了唯一的一個稱為碼點(code point)或碼位的整型數字。其范圍從0到 0x10FFFF,通常以對應的十六進制進行表示。
Unicode規定了多種字符編碼方式,如UTF-8、UTF-16、UTF-32等。
UTF是Unicode Transformation Format(統一碼轉換格式)的縮寫。
不同的編碼方式每個字符占用的字節數不盡相同。對字符對應的碼點值進行編碼時的最小字節單元稱為碼元(code unit,編碼單元或代碼單元)。UTF-8采用8位的單字節碼元,UTF-16采用的16位的雙字節碼元,UTF-32是采用的32位的四字節碼元。
最初Unicode只有UTF-16一種編碼方式,UTF-8和UTF-32是后來發展起來的編碼方式。
UTF-8編碼方式是目前使用最廣泛的一種編碼方式。UTF-8使用的是8位單字節碼元編碼方式,但并非所有的字符都采用1個碼元來編碼,其編碼序列可能為1~4個字節或更長。如英文字符仍占1個字節,而漢字占用3個字節來存儲。
在具體實現中,UTF-8首字節用于識別編碼的字節數。其規則為:除單字節編碼以0開頭外,多字節編碼首字節1的個數用于判斷編碼后的字節長度,然后緊接著以數字0作為終結標志,除首字節外,多字節編碼的后續字節都以10開頭。
UTF-8使用變長字節來編碼能夠節省空間,易于擴展,且與已有的ASCII兼容。
UTF-16和UTF-32采用固定長度的編碼方式也能夠對全球語言的字符或符號進行編碼,但不管是西文還是像亞洲的中日韓都使用統一的長度來存儲,相對來說比較浪費空間。
再回到Python中對字符的編碼方式上來。Python中默認采用UTF-8的編碼方式。在Python中,字符串就是Unicode碼點的序列,為有效存儲字符,這些碼點被轉換成字節序列。這個過程被稱為編碼過程(encode)。
在Python中可以使用encode()函數將字符從一種編碼方式轉換成另外一種編碼方式。關于該函數將在隨后的文章中進行詳細介紹,這里僅給出幾個例子。
s = "武林網VEVB"
su = s.encode()
print('原字符串為:', s)
print('編碼后的字符串為:', su)
其輸出結果如下:
原字符串為: 武林網VEVB
編碼后的字符串為: b'/xe7/xbf/x94/xe5/xae/x87/xe4/xba/xadIT/xe4/xb9/x90/xe5/x9b/xad'
從輸出結果來看,編碼后的字符串前有一個字母"b",表示字符串以字節的形式進行存儲。因為漢字占用3個字節,所以輸出時,漢字被轉換成以/x開始的16進制形式,且有15個之多。而英文字母仍然原樣輸出。
Python中unicodedata模塊中定義了所有unicode字符的屬性。該模塊中定義了一系列的函數來處理與unicode有關的問題。下面簡單介紹這些函數的含義及使用方法。
(1)unicodedata.bidirectional(chr)函數
該函數的作用是以字符串的形式返回分配給字符chr的雙向類。如果沒有定義這樣的值,則返回一個空字符串。
世界上的大多數語言書寫是從左到右的(Left-to-Right,LTR),但有些卻是從右到左的(Right-to-Left,RTL),如阿拉伯語、希伯來語等。但在RTL中,數字的書寫順序或是嵌入到書寫中的英文又是從左到右的,這樣實際上,這些語言的書寫文本表示出雙向性,如果沒有規范,則在計算機處理這些信息時可能會產生歧義。
Unicode中把字符方向性定義為四大類(強、弱、中性和顯示格式),每類下又分為若干小類型。
強(Strong)性下定義了以下三個小類:
L:表示Left-to-Right,即從左到右閱讀,Unicode字符庫中LRM范圍中的字符
R:表示Right-to-Left,即從右到左閱讀,Unicode字符庫中RLM范圍中的字符
AL:表示Right-to-Left阿拉伯語,Unicode字符庫中ALM范圍中的字符;
弱性(Weak)下定義了以下幾個小類:
EN:表示歐洲數字:European Number
ES:表示歐洲數字分隔符:European Number Separator,如加號和減號等。
ET:表示歐洲數字終止符,European Number Terminator,如溫度符號,貨幣符號等
AN:阿拉伯數字,Arabic Number
CS:普通數字分隔符,Common Number Separator,如冒號、逗號,句號,不間斷空格等。
NSM:非間距性標記,Nonspacing Mark,定義在Unicode字符庫中的Mn或Me中的值。
BN:中立性邊界符,Boundary Neutral,默認可忽略的、非字符和控制字符,非顯式給出的其它類型。
中性(Neutral)下的分類有:
B:段落分隔符,Paragraph Separator
S:段內內容分隔符,Segment Separator,Tab
WS:空白,Whitespace,如空格,換行符等
ON:其它中性符號
其它內容,感興趣的讀者可以到unicode官方網站查閱。
bidirectional()函數可以給出一個字符的分類字符串,即上面給出的L、R、NSM等。
import unicodedata
print(unicodedata.bidirectional('A'))
print(unicodedata.bidirectional('8'))
print(unicodedata.bidirectional('{'))
print(unicodedata.bidirectional('+'))
print(unicodedata.bidirectional('※'))
print(unicodedata.bidirectional(u'/u0357'))
輸出結果如下:
L
EN
ON
ES
ON
NSM
(2)unicodedata.category(chr)
該函數是以字符串的形式返回字符chr所屬的基本分類。Unicode中對各個字符按以下類別分類。該函數的作用是返回該字符所屬的類別。
Unicode中的字符可能屬于下表所示的某一種類型。
類別 | 說明 |
---|---|
Lu |
字母,大寫 |
Ll |
字母,小寫 |
Lt |
字母,詞首字母大寫 |
Lm |
字母,修飾符 |
Lo |
字母,其他 |
Mn |
標記,非間距 |
Mc |
標記,間距組合 |
Me |
標記,封閉 |
Nd |
數字,十進制數 |
Nl |
數字,字母 |
No |
數字,其他 |
Pc |
標點,連接符 |
Pd |
標點,短劃線 |
Ps |
標點,開始 |
Pe |
標點,結束 |
Pi |
標點,前引號(根據用途可能表現為類似 Ps 或 Pe) |
Pf |
標點,后引號(根據用途可能表現為類似 Ps 或 Pe) |
Po |
標點,其他 |
Sm |
符號,數學 |
Sc |
符號,貨幣 |
Sk |
符號,修飾符 |
So |
符號,其他 |
Zs |
分隔符,空白 |
Zl |
分隔符,行 |
Zp |
分隔符,段落 |
Cc |
其他,控制 |
Cf |
其他,格式 |
Cs |
其他,代理項 |
Co |
其他,私用 |
Cn |
其他,未賦值(不存在任何字符具有此屬性) |
下面舉幾個例子:
import unicodedata
print(unicodedata.category('A'))
print(unicodedata.category('a'))
print(unicodedata.category('八'))
print(unicodedata.category('8'))
print(unicodedata.category('{'))
輸出結果如下:
Lu
上面結果分別表示大寫字母、小寫字母、其它字符、十進制數字和開始標點符號。
Ll
Lo
Nd
Ps
(3)unicodedata.combining(chr)
該函數以整數形式返回分配給字符的規范組合類,若未定義組合類,則返回0.
每個Unicode字符或編碼點都會給分配一個規范組合類。它本質上指示組合字符附加到基本字符的優先級。規范組合類為0的字符是基本字符,值大于0的字符是組合字符。組合字符一般呈現在基本字符的附近,或附加到基本字符上,或環繞在基本字符周圍。如一些字符是由基本字符加上標或下標構成的。這些上標或下標的形式、位置就是規范組合類的一種。
字符規范組合類的取值如下表所示。
Value |
Description |
---|---|
0: | Spacing, split, enclosing, reordrant, and Tibetan subjoined |
1: | Overlays and interior |
7: | Nuktas |
8: | Hiragana/Katakana voicing marks |
9: | Viramas |
10: | Start of fixed position classes |
199: | End of fixed position classes |
200: | Below left attached |
202: | Below attached |
204: | Below right attached |
208: | Left attached (reordrant around single base character) |
210: | Right attached |
212: | Above left attached |
214: | Above attached |
216: | Above right attached |
218: | Below left |
220: | Below |
222: | Below right |
224: | Left (reordrant around single base character) |
226: | Right |
228: | Above left |
230: | Above |
232: | Above right |
233: | Double below |
234: | Double above |
240: | Below (iota subscript) |
當然上面的規范組合類下并不是都有實例,只是以便今后擴展使用。
函數unicodedata.combining()的作用就是返回某個字符所屬的規范組合類的值。
下面是一些例子:
import unicodedata
print(unicodedata.combining('A'))
print(unicodedata.combining('愛'))
print(unicodedata.combining(u'/u0301'))
print(unicodedata.combining(u'/u0345'))
print(unicodedata.combining(u'/u00D2'))
print(unicodedata.combining(u'/u1dE5'))
print(unicodedata.combining(u'/u0360'))
print(unicodedata.combining(u'/u1DF8'))
print(unicodedata.combining(u'/u0308'))
輸出結果如下:
0
0
230
240
0
230
234
228
230
(4)unicodedata.decimal(chr[, default])
該函數的作用是返回數字字符(包括全角和半角)chr的十進制值,如果沒有定義值,則返回指定的default值,否則會引發ValueError錯誤。
print(unicodedata.decimal('9'))
print(unicodedata.decimal('/u0031'))
print(unicodedata.decimal('/u0041'))
輸出結果如下:
9
1
Traceback (most recent call last):
File "D:/01Lesson/PY/encode01.py", line 33, in <module>
print(unicodedata.decimal('/u0041'))
ValueError: not a decimal
總結了一下這個函數的作用:
在Unicode數據庫中定義的字符,使用isdecimal()函數判斷為True時,該字符作為參數傳遞給該函數時,可以輸出對應的十進制數。
(5)unicodedata.digit(chr[ , default])函數
該函數返回數字字符的對應的阿拉伯數字形式。如果未定義這樣的值,則返回default指定的值,否則將引發ValueError錯誤。
print(unicodedata.digit('1')) #全角數字字符
print(unicodedata.digit('⑨')) #帶圈的數字字符
print(unicodedata.digit('¹')) #上角標數字字符
print(unicodedata.digit('⑶')) # 帶括弧的數字字符
print(unicodedata.digit('⒈')) #帶點的數字字符
輸出結果:
1
9
1
3
1
該函數的參數chr在使用isdigit()函數驗證為True時,能夠正確輸出對應的數字,否則會產生ValueError錯誤。
(6)unicodedata.lookup(name)
該函數的作用是按照給定的名字查詢字符,并返回對應的字符,否則會引發ValueError錯誤。
import unicodedata
print (unicodedata.lookup('LEFT CURLY BRACKET'))
print (unicodedata.lookup('RIGHT SQUARE BRACKET'))
print (unicodedata.lookup('ASTERISK'))
print (unicodedata.lookup('EXCLAMATION MARK'))
print(unicodedata.lookup('TAMIL SYLLABLE TTAA'))
輸出結果如下:
{
(7)unicodedata.mirrored(chr)
]
*
!
??
該函數的作用是以整數形式返回字符chr是否支持鏡像屬性,如果該字符在雙向文本中被識別為“鏡像”字符,則返回1,否則返回0。
鏡像在雙向文本中非常重要,如括號"("在從左到右的文本中作為開始標記的左括號,但在從右到左的文本中應為其鏡像字符:")"。類似這樣的字符則是支持鏡像的字符,再如“{”和“}”等。
print(unicodedata.mirrored('('))
print(unicodedata.mirrored('}'))
print(unicodedata.mirrored('"'))
輸出結果如下所示:
1
1
0
(8) unicodedata.name(chr[, default])
該函數返回指定字符的名稱,如未定義名稱,則返回參數default的值,否則會引發ValueError錯誤。
print (unicodedata.name('%'))
print (unicodedata.name('|'))
print (unicodedata.name('A'))
print (unicodedata.name('a'))
print (unicodedata.name('9'))
print (unicodedata.name('*'))
print (unicodedata.name('@'))
print (unicodedata.name('愛'))
輸出結果如下:
PERCENT SIGN
VERTICAL LINE
LATIN CAPITAL LETTER A
LATIN SMALL LETTER A
DIGIT NINE
ASTERISK
COMMERCIAL AT
CJK UNIFIED IDEOGRAPH-7231
(9)unicodedata.numeric(chr[, default])
該函數返回指定chr對應的數字形式,如果未定義這樣的數字,將返回指定的default的值,否則將觸發ValueError錯誤。
print(unicodedata.numeric('1')) #阿拉伯數字字符
print(unicodedata.numeric('一')) #漢字數字字符
print(unicodedata.numeric('①')) #帶圈的數字字符
print(unicodedata.numeric('叁')) #大寫漢字字符
print(unicodedata.numeric('㈠')) #帶括弧的漢字字符
print(unicodedata.numeric('Ⅲ')) #羅馬數字
輸出結果如下:
1.0
1.0
1.0
3.0
1.0
3.0
實際上該函數的參數chr也是在使用isnumeric()函數驗證該字符為True時才能輸出對應的數字格式。
在使用上面介紹的decimal,digit,numeric三個函數時,首先要保證要作為參數的字符必須是單個字符,其次,作為參數的字符應該分別是十進制數位字符,某種編號的序位字符、用于表序或計量的數字字符。
以上介紹了Unicode編碼的相關知識,并給出了Python中有關Unicode編碼的幾個函數,在內容寫作過程中查閱了官方文檔、眾多網友的介紹,并結合自己的實驗而寫成,如有錯誤,請留言。
新聞熱點
疑難解答