完全解決UnicodeEncodeError與UnicodeDecodeError

字符與字節:計算機存儲的一切數據,都是由一系列的01比特序列組成的,包括文本字符、圖像、音視頻、軟件等等。8位01比特序列構成一個字節。而字符就是一個符號,如一個漢字、一個字母、一個標點。 通俗來講,字節是計算機的語言,字符是人的語言。若是想要讓人和機器通訊交流,就須要進行編碼和解碼。而編解碼的通常套路大概就是:給待編碼的目標集合(字符,或者其餘任何符號、資源等)給定一個惟一ID,把這個ID對應的二進制保存下來,如此種種。網絡


1、ASCII、Unicode、UTF-八、GBK是個什麼鬼

這裏引用一下知乎上盛世唐朝的回答,我的以爲仍是比較通俗易懂的。ui

  • 中國人民經過對ASCII編碼的擴充改造,產生了GB2312編碼,能夠表示6000多經常使用漢字。
  • 漢字實在是太多了,包括繁體和各類字符,因而產生了GBK編碼,它包括了GB2312中的編碼,同時又擴充了不少。
  • 中國是個多民族國家,各個民族幾乎都有本身獨立的語言系統,爲了表示那些字符,繼續把GBK編碼擴充爲GB18030編碼
  • 每一個國家都像中國同樣,把本身的語言編碼,因而出現了各類各樣的編碼,若是你不安裝相應的編碼,就沒法解釋相應編碼想表達的內容。
  • 終於,有個叫ISO的組織看不下去了。他們創造了一種編碼UNICODE,這種編碼很是大,大到能夠容納世界上任何一個文字和標誌。因此只要電腦上有UNICODE這種編碼系統,不管全球哪一種文字,只須要保存文件的時候,保存成UNICODE編碼就能夠被其餘電腦正常解釋。
  • UNICODE在網絡傳輸中,出現了兩個標準UTF-8UTF-16,,分別每次傳輸8個比特位和16個比特位。
  • 有了UTF-8,爲何國內還有這麼多使用GBK等編碼的人?由於UTF-8等編碼體積比較大,佔用空間比較多,若是面向的使用人羣絕大部分都是中國人,用GBK等編碼也能夠。

一言以蔽之,Unicode和GBK、ASCII同是字符集,用來表示字符(符號),前者的表達能力包括後二者;ASCII是最基本的單字節字符集,可直接存儲和傳輸;而UTF-8只是Unicode字符集的一個標準,一種實現方式而已編碼

參考Unicode 和 UTF-8 有什麼區別? - 盛世唐朝的回答 - 知乎spa

若是用一幅圖來表示的話,大概長成下面這樣子:.net

字符與字節的關係

2、encode和decode該用哪個

編碼(encode)就是將字符轉化成字節序列的過程。反之,解碼(decode)就是將字節序列轉換成字符的過程。二者是一個互逆的過程,編碼是爲了存儲傳輸,解碼是爲了顯示閱讀。3d

一、Python的編碼爲何那麼蛋疼?

緣由有二。日誌

其一是由於Python2使用ASCII字符編碼做爲默認編碼方式,而ASCII不能處理中文。那爲何不用UTF-8呢?由於Guido老爹當年正式發佈Python第一個版本的時候是1991年2月,而Unicode是1991年10月發佈的。Python出生時,UTF-8還沒出生。code

其二是由於Python2把字符串的類型搞成兩種,str和unicode,以至於你們常常被搞糊塗了。cdn

二、str與unicode

Python2中字符串有str和unicode兩種類型。str本質上是一串字節序列,由以下示例代碼能夠看出,str類型的」心「打印出來的是十六進制'\xe5\xbf\x83'視頻

>>> sys.stdin.encoding
'UTF-8'
>>> sys.stdout.encoding
'UTF-8'
>>> s = '心'
>>> type(s)
<type 'str'>
>>> s
'\xe5\xbf\x83'
>>>
複製代碼

而unicode類型的u」心「對應的unicode符號是u'\u5fc3'

>>> u = u'心'
>>> type(u)
<type 'unicode'>
>>> u
u'\u5fc3'
>>>
複製代碼

實驗環境爲UTF-8。因此上述三個字節'\xe5\xbf\x83'便是「心」的utf-8編碼的字節碼。這裏簡單說明一下這種轉換關係。

「心」的Unicode編碼爲u'\u5fc3'即U+5fc3,在 U+0800 和 U+FFFF 之間,咱們把5fc3的二進制編碼0101 1111 1100 0011依次替換到1110xxxx 10xxxxxx 10xxxxxx裏的 x 位置上,不夠的位置用 0 來補足。最終咱們獲得一串二進制數據11100101 10111111 10000011,即1110 0101 1011 1111 1000 0011,即\xe5\xbf\x83

三、encode與decode的選擇

咱們要把unicode符號保存到文件或者傳輸到網絡,此時須要進行編碼將其轉換成str類型,因而Python提供了encode方法,反之,則須要進行decode。

encode

>>> u = u'心'
>>> u
u'\u5fc3'
>>> u.encode('utf-8')
'\xe5\xbf\x83'
>>> 
複製代碼

decode

>>> s = '心'
>>> s
'\xe5\xbf\x83'
>>> s.decode('utf-8')
u'\u5fc3'
>>> 
複製代碼

在實驗環境爲UTF-8的條件下,字符串s默認用UTF-8進行編碼,即s的字節碼和u.encode('utf-8')的結果一致。 所以,咱們能夠獲得下圖。

總之,仍是那句話,編碼(encode)就是把字符(符號)轉換成二進制數據的過程,所以unicode到str的轉換要用encode方法,反過來就是用decode方法

encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string.

另外,由第一節字符與字節的關係咱們知道,Unicode編碼能夠表示全部字符集,包括ASCII和GBK。所以,在使用encode/decode的時候必定要對應上相應的字符集,否則將可能會出現UnicodeEncodeError和UnicodeDecodeError。

3、UnicodeEncodeError和UnicodeDecodeError緣由舉例分析

UnicodeEncodeError

主要發生在unicode字符串轉換成str字節序列的時候。例如,

>>> u = u'心'
>>> u.decode('gbk')
複製代碼

錯誤日誌

UnicodeEncodeError: 'ascii' codec can't encode character u'\u5fc3' in position 0: ordinal not in range(128)

爲何會出現UnicodeEncodeError呢?

由於decode是從二進制數據轉換成符號的過程,所以,unicode類型字符串須要先轉換成二進制數據,隱式調用了encode方法,而且使用了Python默認的ascii碼來編碼。而ascii字符集只包含了128個字符,不包括中文字符,所以出現了上述錯誤。

要解決該錯誤,則必須指定正確的編碼規則來使用encode方法,如GBK。

>>> u = u'心'
>>> u.encode('gbk')
'\xd0\xc4'
>>> u.encode('gbk').decode('gbk')
u'\u5fc3'
>>> 
複製代碼

其中'\xd0\xc4'是「心」字在GBK字符集中的編碼(也能夠理解爲編號ID)。

UnicodeDecodeError

主要發生在str類型字節序列轉換成unicode類型字符串的時候。例如,

>>> s = '心'
>>> s.encode('gbk')
複製代碼

錯誤日誌

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

爲何會出現UnicodeDecodeError呢?

由於encode是從符號轉換成二進制數據的過程,所以str類型字節序列須要先轉換成符號,隱式調用了decode方法,而且使用了Python默認的ascii碼來解碼。而ascii字符集只包含了128個字符,不包括中文字符,所以出現了上述錯誤。若是用GBK來解碼是否能夠呢?好比直接執行s.decode('gbk'),答案是不能夠。

要解決該錯誤,則必須指定正確的編碼規則來使用decode方法,如UTF-8。

>>> s = '心'
>>> s.decode('utf-8').encode('gbk')
'\xd0\xc4'
>>> 
複製代碼

參考blog.csdn.net/trochiluses…

而若是涉及到UTF-8和GBK編碼的相互轉換,則只需遵循下圖便可作到正確轉換。本質上是藉助了字符是不變的,而Unicode字符集中包括了GBK的全部字符這一基本事實。

UTF-8編碼和GBK編碼的相互轉換

爲了不出現UnicodeEncodeError/UnicodeDecodeError或者亂碼的問題,encode和decode方法必定要成對使用,而且採用正確的字符集和編解碼規則。 最佳實踐是,建議採用」三明治「處理思想,僅在」出入口「進行encode/decode操做。

簡單總結一下,本文粗略介紹了一下Unicode、GBK、ASCII以及UTF-8之間的關係;明確了字符與字節的關係;舉例介紹了Encode/Decode使用時的注意事項;並舉例分析了UnicodeEncodeError/UnicodeDecodeError產生的緣由;總結了一些經驗規則;然而,最重要仍是文中的三張圖。

相關文章
相關標籤/搜索