字符串是Python中最經常使用的數據類型,並且不少時候你會用到一些不屬於標準ASCII字符集的字符,這時候代碼就極可能拋出UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 10: ordinal not in range(128)異常。這種異常在Python中很容易遇到,尤爲是在Python2.x中,是一個很讓初學者費解頭疼的問題。不過,若是你理解了Python的Unicode,並在編碼中遵循必定的原則,這種編碼問題仍是比較容易理解和解決的。python
字符串在Python內部的表示是unicode編碼,所以,在作編碼轉換時,一般須要以unicode做爲中間編碼,即先將其餘編碼的字符串解碼(decode)成unicode,再從unicode編碼(encode)成另外一種編碼。可是,Python 2.x的默認編碼格式是ASCII,就是說,在沒有指定Python源碼編碼格式的狀況下,源碼中的全部字符都會被默認爲ASCII碼。也由於這個根本緣由,在Python 2.x中常常會遇到UnicodeDecodeError或者UnicodeEncodeError的異常。編碼
Unicode是一種字符集,它爲每一種現代或古代使用的文字系統中出現的每個字符都提供了統一的序列號,規定了符號的二進制代碼,但沒有規定這個二進制代碼應該如何存儲。也就是說:Unicode的編碼方式是固定的,可是實現方式根據不一樣的須要有跟多種,常見的有UTF-八、UTF-16和UTF-32等。設計
爲了可以處理Unicode數據,同時兼容Python某些內部模塊,Python 2.x中提供了Unicode這種數據類型,經過decode和encode方法能夠將其它編碼和Unicode編碼相互轉化,但同時也引入了UnicodeDecodeError和UnicodeEncodeError異常。。code
Python中常見的幾種編碼異常有SyntaxError: Non-ASCII character、UnicodeDecodeError和UnicodeEncodeError等。下面依次舉例說明一下:utf-8
這種異常最不容易出現,也最容易處理,主要緣由是Python源碼文件中有非ASCII字符,並且同時沒有聲明源碼編碼格式,例如:ci
s = '中文' print s # 拋出異常
這個異常有時候會在調用decode方法時出現,緣由是Python打算將其餘編碼的字符轉化爲Unicode編碼,可是字符自己的編碼格式和decode方法傳入的編碼格式不一致,例如:unicode
#!/usr/bin/python # -*- coding: utf-8 -*- s = '中文' s.decode('gb2312') # UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 2-3: illegal multibyte sequence print s
上面這段代碼中字符串s的編碼格式是utf-8,可是在使用decode方法轉化爲Unicode編碼時傳入的參數是‘gb2312’,所以在轉化的時候拋出UnicodeDecodeError異常。還有一種狀況是在encode的時候:字符串
#!/usr/bin/python # -*- coding: utf-8 -*- s = '中文' s.encode('gb2312') # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) print s
錯誤的使用decode和encode方法會出現這種異常,好比:使用decode方法將Unicode字符串轉化的時候:get
#!/usr/bin/python # -*- coding: utf-8 -*- s = u'中文' s.decode('utf-8') # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128) print s
固然,除了上面列出的幾種出現異常的狀況以外還有不少可能出現異常的例子,這裏就不在一一說明了。源碼
對於以上的幾個異常,有如下幾個處理的方法和原則。
在PEP 0263 -- Defining Python Source Code Encodings中提出了對Python編碼問題的最基本的解決方法:在Python源碼文件中聲明編碼格式,最多見的聲明方式以下:
#!/usr/bin/python # -*- coding: <encoding name> -*-
其中是代碼所須要的編碼格式,它能夠是任意一種Python支持的格式,通常都會使用utf-8的編碼格式。
u'中文'
替代 '中文'
str1 = '中文編碼' str2 = u'中文編碼'
Python中有以上兩種聲明字符串變量的方式,它們的主要區別是編碼格式的不一樣,其中,str1的編碼格式和Python文件聲明的編碼格式一致,而str2的編碼格式則是Unicode。若是你要聲明的字符串變量中存在非ASCII的字符,那麼最好使用str2的聲明格式,這樣你就能夠不須要執行decode,直接對字符串進行操做,能夠避免一些出現異常的狀況。
Python中出現這麼多編碼問題的根本緣由是Python 2.x的默認編碼格式是ASCII,因此你也能夠經過如下的方式修改默認的編碼格式:
import sys sys.setdefaultencoding('utf-8')
這種方法是能夠解決部分編碼問題,可是同時也會引入不少其餘問題,得不償失,不建議使用這種方式。
最後分享一個終極原則:decode early, unicode everywhere, encode late,即:在輸入或者聲明字符串的時候,儘早地使用decode方法將字符串轉化成unicode編碼格式;而後在程序內使用字符串的時候統一使用unicode格式進行處理,好比字符串拼接、字符串替換、獲取字符串的長度等操做;最後,在輸出字符串的時候(控制檯/網頁/文件),經過encode方法將字符串轉化爲你所想要的編碼格式,好比utf-8等。
按照這個原則處理Python的字符串,基本上能夠解決全部的編碼問題(只要你的代碼和Python環境沒有問題)。。。
額,最後一個方法,升級Python 2.x,使用Python 3.x版本。。這樣說主要是爲了吐槽Python 2.x的編碼設計問題。固然,升級到Python 3.x確定能夠解決大部分由於編碼產生的異常問題。畢竟Python 3.x版本對字符串這部分仍是作了至關大的改進的,具體的下面會說。。。。
在Python 3.0以後的版本中,全部的字符串都是使用Unicode編碼的字符串序列,同時還有如下幾個改進:
因此,對於Python 3.x來講,編碼問題已經再也不是個大的問題,基本上不多遇到上述的幾個異常。關於Python 2.x str&unicode和Python 3.x str&bytes的更多說明和對比,你們能夠看一下:Python中字符編碼的總結和對比
PS: 該文章轉自個人博客:Python的中文編碼問題
Over!