python 中 string 和 unicode 字符串編碼問題

先要弄清楚的是,在python裏,string object和unicode object是兩種不同的類型。

 原文博主--http://blog.csdn.net/feisan
string object是由characters組成的sequence,而unicode object是Unicode code units組成的sequence。

string裏的character是有多種編碼方式的,比如單字節的ASCII,雙字節的GB2312等等,再比如UTF-8。很明顯要想解讀string,必需知道string裏的character是用哪種編碼方式,然後才能進行。

Unicode code unit又是什麼東西呢?一個Unicode code unit是一個16-bit或者32-bit的數值,每個數值代表一個unicode符號。在python裏,16-bit的unicode,對應的是ucs2編碼。32-bit對應的是ucs4編碼。是不是感覺string裏character的編碼沒什麼區別?反正我現在腦子裏就是這樣一個印象:在Python裏,ucs2或者ucs4編碼的,我們叫做unicode object,其他編碼的我們就叫做string。

至於python裏的unicode到底是ucs2還是ucs4的,可以在編譯時指定。例如Linux下,要用ucs2做unicode的編碼,可以這樣
# ./configure --enable-unicode=ucs2 
# make
# make install
下載的Windows預編譯版本,一般都是ucs2的。要想知道某個python運行環境是ucs2還是ucs4,可以查看sys.maxunicde,65535就是ucs2的,另一個很大的數值就是ucs4。

下面我們看看string和unicode在python裏的不同
我們先看看在簡體中文Windows 2003系統下,系統編碼是GBK
>>> a = '你好'
>>> a
'/xc4/xe3/xba/xc3'
>>> b = u'你好'
>>> b
u'/u4f60/u597d'
>>> print a
你好
>>> print b
你好
>>> a.__class__
<type 'str'>
>>> b.__class__
<type 'unicode'>
>>> len(a)
4
>>> len(b)
2

在一個系統編碼爲UTF-8的Linux環境下
>>> a = '你好'
>>> a
'/xe4/xbd/xa0/xe5/xa5/xbd'
>>> b = u'你好'
>>> b
u'/u4f60/u597d'
>>> print a
你好
>>> print b
你好
>>> a.__class__
<type 'str'>
>>> b.__class__
<type 'unicode'>
>>> len(a)
6
>>> len(b)
2

如何?簡單總結一下:
1、string直接用引號來表示,unicode在引號前加一個u
2、直接輸入的string常量會用系統缺省編碼方式來編碼,例如在GBK環境下,'你好'會編碼成'/xc4/xe3/xba/xc3',而在UTF-8環境下就成了'/xe4/xbd/xa0/xe5/xa5/xbd'。
3、len(string)返回string的字節數,len(unicode)返回的是字符數
4、很重要的一點,print unicode不會亂碼。現在我們常用的Linux、Windows系統,都是支持unicode的,版本太老的不算。比如Windows 2003支持ucs2,所以在中文Windows2003下,除了可以正常顯示缺省的GBK編碼外,還可以正常顯示ucs2編碼。舉個例子,還是在中文Windows 2003的GBK環境下:
>>>a = '/xe4/xbd/xa0/xe5/xa5/xbd' # UTF-8的'你好'
>>> print a
浣犲ソ
>>> b = unicode(a, "UTF-8")
>>> b
u'/u4f60/u597d'
>>> print b
你好

應該明白了吧?

下面再說說string和unicode的相互轉換,什麼unicode()、decode()、encode()、codecs之類的。

繼續。

先說一下,前面提到,print(string)的時候,如果string是按當前環境編碼方式編碼的,可以正常輸出,不會亂碼;如果string不是當前編碼的,就會亂碼。而print(unicode)是不會亂碼的。why?應爲print(unicode)的時候,會把unicode先轉成當前編碼,然後再輸出。我沒看過print的源碼,不過估計是這樣的。

string轉unicode或者unicode轉string,是很常見的操作。

string和unicode都有decode()和encode()方法。decode是string2unicode,encode自然就是unicode2string。看個例子(中文Windows2003下):
>>> a = '你好'
>>> a
'/xc4/xe3/xba/xc3'
>>> b = u'你好'
>>> c = a.decode('gbk') #gbk string to unicode
>>> b == c
True
>>> c
u'/u4f60/u597d'
>>> d = b.encode('gbk') #unicode to gbk string
>>> d == a
True
>>> d
'/xc4/xe3/xba/xc3'
>>> e = b.encode('utf-8') #unicode to utf-8 string
>>> e
'/xe4/xbd/xa0/xe5/xa5/xbd'

decode或者encode的時候,如果不指定編碼方式,會按照缺省編碼方式來處理。查看、設置缺省編碼方式可以這樣做:
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> reload(sys) 
<module 'sys' (built-in)>
>>> sys.setdefaultencoding('gbk')
上面調用sys.setdefaultencoding()的時候先reload一下sys module,原因是python啓動時缺省會import site.py, 而site.py會del sys.setdefaultencoding(),所以需要reload(sys)。具體可以看看site.py的源碼。

接下來說說unicode()函數。其實unicode函數就是調用string的decode()方法,把string轉成unicode,例如:
>>> a = '你好'
>>> b = unicode(a)
>>> b
u'/u4f60/u597d'
>>> c = a.decode('gbk')
>>> c
u'/u4f60/u597d'
>>> print b, c, b==c
你好 你好 True

下一部分說說codec

最後說說關於codecs。所謂的codec就是編碼器和解碼器(encoder and decoder)的集合。除了各種字符串編碼的codec,還有各種文件格式的codec,比如壓縮、解壓縮的,圖像的,音頻的,等等。我們這裏說的當然是跟字符串編碼相關的了。

看看代碼
>>> import codecs
>>> gbk=codecs.lookup('gbk')
>>> gbk
<codecs.CodecInfo object for encoding gbk at 0xad3ea0>
>>> gbk.decode("你好")
(u'/u4f60/u597d', 4)
>>> gbk.encode(u'/u4f60/u597d')
('/xc4/xe3/xba/xc3', 2)

發佈了16 篇原創文章 · 獲贊 16 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章