Python中GBK, UTF-8和Unicode的編碼問題

來源:互聯網
上載者:User

標籤:

編碼問題,一直是使用python2時的一塊心病。幾乎所有的控制台輸入輸出、IO操作和HTTP操作都會涉及如下的編碼問題:
UnicodeDecodeError:‘ascii’codec can’t decodebyte0xc4inposition10:ordinalnotinrange(128)

這究竟是是個什麼東西?!有時稀裡糊塗地用一坨encode(),decode()之類的函數讓程式能跑對了,可是下次遇到非ASCII編碼時又悲劇了。

那麼Python 2.x中的字串究竟是個什麼呢?

基本編碼知識

在瞭解Python中字串(String)的本質前,我們需要知道ASCII、GBK、UTF-8和Unicode的關係究竟幾何。
我們知道,任何字串都是一串二進位位元組的序列,而ASCII碼是最經典的編碼方式,它將序列中的每個位元組理解為一個字元,可表示阿拉伯數字、字母在內的128個不同字元。很明顯,漢字在ascii中是無法表示的。
為了讓電腦能夠顯示、處理漢字,勤勞樸實的中國人民制定了GBK(GB2312的擴充)編碼,這是一種相容ASCII的不定長(長度為1-2)編碼,對於基本的128個字元仍舊用一個位元組表示,但“翔”這樣的中文就用兩個位元組表示:

UTF-8與GBK類似,也是一種相容ASCII碼的不定長編碼形式,它的長度變化更大,因此可以表示幾乎所有世界文字。具體細節可參考維基:http://zh.wikipedia.org/wiki/UTF-8

Unicode是一種定長的編碼方式(同ASCII),不過它是每2位元組認為是一個字元,如ASCII中0x61表示‘a‘,在Unicode中用0x0061表示‘a‘,它可映射所有文字,而且對於多種寫法的字,如強/強,它都可以唯一地區分它們。

由於Unicode編碼的字串體積很大,因此一般來說Unicode編碼只是文字在記憶體中的內在形式,具體的儲存(如檔案、網頁等)都需要靠外在的編碼(UTF-8、GBK等)詮釋。

Python2.x中字串的本質

Python中實際上有兩種字串,分別是str類型和unicode類型,這兩者都是basestring的衍生類別。它們的區別如下:

字串類型

常量子串表示

記憶體中表示

len()

len含義

str

S=“呵呵”

與源碼檔案完全一致,一坨二進位編碼

若源碼檔案為UTF-8編碼,
len(S)=6

位元組數

unicode

S=u“呵呵”

Unicode編碼

len(S)=2

字數

str類型的本質就是一坨二進位串,源檔案(或擷取的網頁)的編碼是怎樣,它就跟著是怎樣。實際上Python並不清楚某個str字串到底是什麼編碼。這也就解釋了為什麼我們需要在python檔案的開頭標定該檔案的編碼是什麼,如:

# encoding: utf-8

也解釋了為什麼len()一個str類型的字串,只會返回它在記憶體中佔用的位元組數,而非文字數
相比於str,unicode是真正的字串。Python明確地知道它的編碼,所以可以很自信地獲得一個字串的實際字數。

字串編碼轉換:encode()和decode()

Python最常用的編碼轉換函式是encode()和decode(),他們的本質是:unicode和str的互相轉換
具體而言:
encode(encoding): 將unicode轉換為str,並使用encoding編碼;
decode(encoding):將str轉換為unicode,其中str以encoding編碼。

我們來看一個例子:

#encoding: utf-8s="你好"# 整個檔案是UTF-8編碼,所以這裡的字串也是UTF-8u=s.decode("utf-8")# 將utf-8的str轉換為unicodeg=u.encode(‘GBK‘)# 將unicode轉換為str,編碼為GBKprinttype(s),"len=",len(s)# 輸出:<type ‘str‘> len= 6,utf-8每個漢字佔3位元組printtype(u),"len=",len(u)# 輸出:<type ‘str‘> len= 6,unicode統計的是字數printtype(g),"len=",len(g)# 輸出:g = u.encode(‘GBK‘),GBK每個漢字佔2位元組prints# 在GBK/ANSI環境下(如Windows),輸出亂碼,#因為此時螢幕輸出會被強制理解為GBK;Linux下顯示正常printg# 在Windows下輸出“你好”,#Linux(UTF-8環境)下報錯,原因同上。

在Windows7(中文)下運行結果如下:

<type‘str‘>len= 6<type‘unicode‘>len= 2<type‘str‘>len= 4浣犲ソ你好Traceback (most recent call last):  File "C:/Users/Sunicy/Desktop/encode.py", line 15, in<module>g.decode(‘utf-8‘)  File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode    return codecs.utf_8_decode(input, errors, True)UnicodeDecodeError: ‘utf8‘ codec can‘t decode byte 0xc4 in position 0: invalid continuation byte
判斷變數是否為字串

我們知道Python中判斷一個變數是否為某個類型使用isinstance(變數, 類型)函數,如

isinstance(1.2,float)

傳回值為True

那麼判斷變數是不是字串能不能用

isinstance(s,str)

呢?

答案是否定的。
現在我們知道除了str之外,unicode類型也是字串,因此上述代碼如果遇到unicode字串,就返回False。
直觀地改進是既判斷str又判斷unicode:

isinstance(s,str)orisinstance(s,unicode)

不過這個方法有效,但是有點傻。既然str和unicode都派生自basestring,那麼實際上以basestring作為類型是最穩妥的:

isinstance(s,basestring)

下面是一組例子:

isinstance("aaa",str)# -> Trueisinstance({},dict)# -> Trueisinstance([1,],list)# -> Trueisinstance("aaa",list)# -> Falseisinstance("你",str)# -> Falseisinstance("你好",basestring)# -> Trueisinstance("aaa",basestring)# -> True
總結
  1. unicode是支援所有文字的統一編碼,但一般只用作文字的內部表示,檔案、網頁(也是檔案)、螢幕輸入輸出等處均需使用具體的外在編碼,如GBK、UTF-8等;
  2. encode和decode都是針對unicode進行“編碼”和“解碼”,所以encode是unicode->str的過程,decode是str->unicode的過程;
  3. unicode和str是一對孿生兄弟,來自basestring,所以用isinstance(s, basestring)來判斷s是否為字串。

Python中GBK, UTF-8和Unicode的編碼問題

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.