編碼問題,一直是使用python2時的一塊心病。幾乎所有的控制台輸入輸出、io操作和http操作都會涉及如下的編碼問題:
unicodedecodeerror:『這究竟是是個什麼東西?!有時稀里糊塗地用一坨encode(),decode()之類的函式讓程式能跑對了,可是下次遇到非ascii編碼時又悲劇了。ascii
』codec can
』t decode
byte
0xc4
inposition 10:
ordinal
notin
range
(128
)
那麼python 2.x中的字串究竟是個什麼呢?
在了解python中字串(string)的本質前,我們需要知道ascii、gbk、utf-8和unicode的關係究竟幾何。
我們知道,任何字串都是一串二進位制位元組的序列,而ascii碼是最經典的編碼方式,它將序列中的每個位元組理解為乙個字元,可表示阿拉伯數字、字母在內的128個不同字元。很明顯,漢字在ascii中是無法表示的。
為了讓計算機能夠顯示、處理漢字,勤勞樸實的中國人民制定了gbk(gb2312的擴充套件)編碼,這是一種相容ascii的不定長(長度為1-2)編碼,對於基本的128個字元仍舊用乙個位元組表示,但「翔」這樣的中文就用兩個位元組表示:
utf-8與gbk類似,也是一種相容ascii碼的不定長編碼形式,它的長度變化更大,因此可以表示幾乎所有世界文字。具體細節可參考維基:
unicode是一種定長的編碼方式(同ascii),不過它是每2位元組認為是乙個字元,如ascii中0x61表示'a',在unicode中用0x0061表示'a',它可對映所有文字,而且對於多種寫法的字,如強/強,它都可以唯一地區分它們。
由於unicode編碼的字串體積很大,因此一般來說unicode編碼只是文字在記憶體中的內在形式,具體的儲存(如檔案、網頁等)都需要靠外在的編碼(utf-8、gbk等)詮釋。
python中實際上有兩種字串,分別是str型別和unicode型別,這兩者都是basestring的派生類。它們的區別如下:
字串型別
常量子串表示
記憶體中表示
len()
len含義
strs=「呵呵」
與原始碼檔案完全一致,一坨二進位制編碼
若原始碼檔案為utf-8編碼,
len(s)=6
位元組數unicode
s=u「呵呵」
unicode編碼
len(s)=2
字數str型別的本質就是一坨二進位制串,原始檔(或獲取的網頁)的編碼是怎樣,它就跟著是怎樣。實際上python並不清楚某個str字串到底是什麼編碼。這也就解釋了為什麼我們需要在python檔案的開頭標定該檔案的編碼是什麼,如:
# encoding: utf-8也解釋了為什麼len()乙個str型別的字串,只會返回它在記憶體中占用的位元組數,而非文字數。
相比於str,unicode是真正的字串。python明確地知道它的編碼,所以可以很自信地獲得乙個字串的實際字數。
python最常用的編碼轉換函式是encode()和decode(),他們的本質是:unicode和str的互相轉換。
具體而言:
encode(encoding): 將unicode轉換為str,並使用encoding編碼;
decode(encoding):將str轉換為unicode,其中str以encoding編碼。
我們來看乙個例子:
#encoding: utf-8s =在windows7(中文)下執行結果如下:"你好"
# 整個檔案是utf-8編碼,所以這裡的字串也是utf-8u =
s.decode
("utf-8"
)# 將utf-8的str轉換為unicodeg =
u.encode
('gbk'
)# 將unicode轉換為str,編碼為gbk
type(s
),"len="
,len(s
)# 輸出: len= 6,utf-8每個漢字佔3位元組
type(u
),"len="
,len(u
)# 輸出: len= 6,unicode統計的是字數
type(g
),"len="
,len(g
)# 輸出:g = u.encode('gbk'),gbk每個漢字佔2位元組
s # 在gbk/ansi環境下(如windows),輸出亂碼,
#因為此時螢幕輸出會被強制理解為gbk;linux下顯示正常
g # 在windows下輸出「你好」,
#linux(utf-8環境)下報錯,原因同上。
len=6我們知道python中判斷乙個變數是否為某個型別使用isinstance(變數, 型別)函式,如len=
2len=4
浣犲ソ你好
traceback
(most recent call
last
):file
"c:/users/sunicy/desktop/encode.py"
,line 15,
ing.decode
('utf-8'
)file
"c:\python27\lib\encodings\utf_8.py"
,line 16,
indecode
return
codecs
.utf_8_decode
(input
,errors
,true
)unicodedecodeerror
:'utf8'
codec can
't decode byte 0xc4 in position 0: invalid continuation byte
isinstance返回值為true(1.2
,float
)
那麼判斷變數是不是字串能不能用
isinstance(s呢?,str
)
答案是否定的。
現在我們知道除了str之外,unicode型別也是字串,因此上述**如果遇到unicode字串,就返回false。
直觀地改進是既判斷str又判斷unicode:
isinstance(s不過這個方法有效,但是有點傻。既然str和unicode都派生自basestring,那麼實際上以basestring作為型別是最穩妥的:,str)or
isinstance(s
,unicode
)
isinstance(s下面是一組例子:,basestring
)
isinstanceunicode是支援所有文字的統一編碼,但一般只用作文字的內部表示,檔案、網頁(也是檔案)、螢幕輸入輸出等處均需使用具體的外在編碼,如gbk、utf-8等;("aaa"
,str
)# -> true
isinstance
({},
dict
)# -> true
isinstance([1
,],list
)# -> true
isinstance
("aaa"
,list
)# -> false
isinstance
("你"
,str
)# -> false
isinstance
("你好"
,basestring
)# -> true
isinstance
("aaa"
,basestring
)# -> true
encode和decode都是針對unicode進行「編碼」和「解碼」,所以encode是unicode->str的過程,decode是str->unicode的過程;
unicode和str是一對孿生兄弟,來自basestring,所以用isinstance(s, basestring)來判斷s是否為字串。
python中gbk, utf-8和unicode的編碼問題, 感謝原作者分享。
Python編碼問題
tag python,encoding,unicode 現有的字元編碼 ascii,gbk,gb2312,utf 8,unicode.unicode可以用來表示所有語言的字元,而且是定長雙位元組 也有四位元組的 編碼,包括英文本母在內。python中定義乙個unicode字串和定義乙個普通字串一樣簡...
python編碼問題
python裡面基本上要考慮三種編碼格式 1 原始檔編碼 在檔案頭部使用coding宣告。告訴python直譯器該 檔案所使用的字符集。usr bin python coding utf8 2 內部編碼 檔案中的字串,經過decode以後,被轉換為統一的unicode格式的內部資料,類似於u uni...
Python編碼問題
python裡面基本上要考慮三種編碼格式 1 原始檔編碼 在檔案頭部使用coding宣告。告訴python直譯器該 檔案所使用的字符集。usr bin python coding utf8 2 內部編碼 檔案中的字串,經過decode以後,被轉換為統一的unicode格式的內部資料,類似於u uni...