python2 中文編碼問題小結
最近處理中文資料,python2各種編碼問題,看了好多部落格和文章,終於弄懂了一些,所以在這裡總結一發。供大家學習和參考!
1.編碼
(1)ASCII碼
ASCII碼是規定的最早的計算機系統將英文文字轉為數字儲存的編碼方式,一共規定了128個字元的編碼,即7個bit。而1byte=8bit,所以佔一個位元組的ASCII碼的最高位(沒用到)為0。
(2)Unicode
由於ASCII碼只包含了大小寫英文字母、數字和一些符號,如果用來表示其他語言,那麼是不行的。因此產生了一些非ASCII編碼方式。
簡體中文常見的編碼方式是GB2312,使用兩個位元組表示一個漢字,所以理論上最多可以表示256x256=65536個符號。
但是每個地方的編碼標準都不一樣,如何統一呢?Unicode就出現了。
Unicode叫做萬國碼,採用32位二進位制(4位元組)表示一個字元。但是需要注意的是,Unicode只是一個符號集(指定字元到二進位制數之間的對應關係),它只規定了符號的二進位制程式碼,卻沒有規定這個二進位制程式碼應該如何儲存。
(3)UTF-8
Unicode的實現方式有很多種,比如
- UTF-8 :(變長的編碼方式,可以使用2~4個位元組表示一個符號,根據不同的符號而變化位元組長度)
- UTF-16:(變長的編碼方式,可以使用2~4個位元組表示一個符號,根據不同的符號而變化位元組長度)
- UTF-32:(每個字元固定佔4位元組)
而UTF-8(8-bit Unicode Transformation Format)是在網際網路上使用最廣的一種Unicode的實現方式。
2.Python 編碼
python2預設以ASCII編碼,但是在實際編碼過程中,我們會用到很多中文,為了不使包含中文的程式報錯,也是為了符合國際通用慣例,一般將我們的檔案編碼設定為utf-8格式。
如何設定:一般在檔案開頭宣告
# -*- coding:utf-8 -*-
Python中有兩個常用的由basestring派生出來的表示字串的型別:str, unicode。
其中,str類似於C中的字元陣列或者Java中的byte陣列。
對於unicode型別,Python在記憶體中儲存和使用的時候是按照UTF-8方式,在程式碼中的表示為字串前加u。
而unicode與str之間的轉換,則用到了encode和deocde方法。
decode解碼:表示將一個(str)字串按照給定的編碼解析為unicode型別,encode編碼:表示將一個unicode字串按照指定編碼解析為位元組陣列(str)
3.sys.setdefaultencoding(‘utf-8’) 問題
為什麼我們有時候遇到編碼問題時,還經常看到一種解決方式reload(sys),sys.setdefaultencoding(‘utf-8’) ?
若str物件呼叫encode會預設先按系統預設編碼方式 decode成unicode物件再encode,忽視了中間預設的decode往往導致報錯。
比如有如下程式碼:
# -*- coding: utf-8 -*-
s = '中文字元' # 這裡的 str 是 str 型別的,而不是 unicode
s.encode('gb2312')
這句程式碼將 s 重新編碼為 gb2312 的格式,即進行 unicode -> str 的轉換。因為 s 本身就是 str 型別的,因此
Python 會自動的先將 s 解碼為 unicode ,然後再編碼成 gb2312。因為解碼是python自動進行的,我們沒有指明解碼方式,python 就會使用 sys.defaultencoding 指明的方式來解碼。很多情況下 sys.defaultencoding為ANSCII,如果 s 不是這個型別就會出錯。
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position
0: ordinal not in range(128)
對於這種情況,我們有兩種方法來改正錯誤:
(1)明確的指示出 s 的編碼方式
#! /usr/bin/env python
# -*- coding: utf-8 -*-
s = '中文字元'
s.decode('utf-8').encode('gb2312')
(2)更改 sys.defaultencoding 為檔案的編碼方式
# -*- coding: utf-8 -*-
import sys
reload(sys) # Python2.5 初始化後刪除了 sys.setdefaultencoding 方法,我們需要重新載入
sys.setdefaultencoding('utf-8')
str = '中文字元'
str.encode('gb2312')
總結:
1. 編碼問題在python2中還是挺麻煩的,尤其是處理中文,裡面的坑大概我都遇到過了。我建議一上來先加coding那句話,順帶把reload也加上吧。這樣避免之後程式報錯又重新來找問題。(我也有看到文章說reload(sys)似乎並不是很好,我覺得其實最好的辦法是我們都換python3 吧^_^)
2. 搞懂Unicode和UTF-8之間的關係(只是實現方式)。
3. 搞懂 python中編碼encode和解碼decode是在幹什麼。str到unicode為解碼,unicode到str為編碼。如果某種str到另一種str,其中會先用系統預設方式decode解碼,再encode編碼。
參考部落格:
阮一峰-字元編碼筆記:ASCII,Unicode和UTF-8
(寫的很贊啊!我的很多地方都是看了他的部落格弄懂的)
聊一聊 Python 2 中的編碼
這篇文章encode,decode寫的很清楚呀~而且也非常通俗易懂,膜拜大佬~