首先我們在編寫python代碼文件時,文件本身會采用一種編碼格式,如 utf-8 或 gbk
這時我們需要在python文件的開頭設置文件的編碼格式,以告訴編譯器。
如果文件的編碼格式是 utf-8, 則在文件的第一行需要添加如下語句
#coding=utf-8
如果文件的編碼格式是 gbk, 則在文件的第一行需要添加如下語句
#coding=gbk
如果設置為utf-8的格式,在linux執行,中文處理,包括顯示沒任何問題。
但是如果設置為utf-8的格式,在window下,在命令行下執行時,發現利用 print打印中文會出現亂碼。
原因是因為,雖然文件聲明為utf-8,且用utf-8的編碼保存的源文件。但是windows的本地默認編碼是cp936,也就是gbk編碼,所以在控制台直接打印utf-8的字符串就顯示亂碼了。 注意,實際上只是顯示有問題,入庫等處理並沒問題。
這有兩種解決方案。
一、方案一:
將文件的編碼格式改為gbk,並在文件的第一行改為#coding=gbk,這時處理中文就沒問題。
但這個方案帶來的問題,如果該文件放到Linux下可能會顯示出問題。因為一般linux機器下沒有gbk的字符集。
二、方案二
文件還是采用utf-8的編碼,文件頭的第一行依然是#coding=utf-8
這時在print 中文時需要進行下編碼,代碼如:
print "中文".decode('utf-8').encode(sys.getfilesystemencoding())
注意:因為用到了sys模塊,需要在語句執行添加 import sys
這樣帶來的問題,print語句比較臃腫,可以考慮自己封裝下.
三、關於 decode 方法和 encode 方法
字符串在Python內部的表示是unicode編碼。在做編碼轉換時,通常需要以unicode作為中間編碼,即先將其他編碼的字符串解碼(decode)成unicode,再從unicode編碼(encode)成另一種編碼。
decode的作用是將其他編碼的字符串轉換成unicode編碼, 其參數就是字符串的當前編碼格式。如str.decode('utf-8'),表示將utf-8編碼的字符串轉換成unicode編碼。
encode的作用是將unicode編碼轉換成其他編碼的字符串, 其參數就是希望轉換后的編碼格式。如str.encode('utf-8'),表示將unicode編碼的字符串轉換成utf-8編碼。
不能直接將一種編碼(非unicode)的字符串利用encode方法直接轉換為其它的編碼格式。
注意:unicode 和 其它的編碼字符串在python 是完全不同的兩種數據類型,unicode的字符串時unicode類型的, 其它的是str類型。
在python中,對於字面字符串我們可以在字面字符串前加u把該字符串聲明為unicode類型的。
下面我們來看一個例子了解unicode和str類型的區別
>>> s='測試' >>> us=u'測試unicode' >>> print isinstance(s,str) True >>> print isinstance(s,unicode) False >>> print isinstance(us,str) False >>> print isinstance(us,unicode) True >>> print isinstance(us.encode('utf-8'),unicode) False >>> print isinstance(us.encode('utf-8'),str) True >>> print isinstance(s.decode('gbk'),unicode) #是在windows下執行,默認的s是gbk編碼 True
利用第三方包 chardet的detect方法可以檢查一個字符串具體的編碼格式,如:
>>> import chardet >>> chardet.detect('中文') {'confidence': 0.682639754276994, 'encoding': 'KOI8-R'} #在window下執行的 >>> chardet.detect('str123') {'confidence': 1.0, 'encoding': 'ascii'} >>> chardet.detect(u'中文') #無法對unicode類型進行檢查 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Anaconda2\lib\site-packages\chardet\__init__.py", line 25, in de raise ValueError('Expected a bytes object, not a unicode object') ValueError: Expected a bytes object, not a unicode object >>> chardet.detect(u'中文'.encode('utf8')) #參數為utf-8的 {'confidence': 0.7525, 'encoding': 'utf-8'}
四、與中文相關的常見處理場景
在程序編寫中,一般涉及到中文我們才需要編解碼。 通常有如下幾種場景:
1、將文件中硬編碼的中文字符串利用print輸出,就如上面介紹的例子:
str = "中文"
print str
str = str.decode('utf-8').encode(sys.getfilesystemencoding())
print str
上面的代碼假設文件的編碼格式為utf-8,當在windows命令行下執行時,第一個print語句輸出的是亂碼。
我們先調用decode方法將其轉為 unicode編碼,然后在調用encode方法轉為系統編碼的格式。
2、當我們用raw_input從控制台獲取字符串時
這時獲取到的字符串的編碼時系統編碼,不一定是utf-8,這時我們想要轉為utf-8,可以用如下的方法
msg = raw_input(">")
msg = msg.decode(sys.getfilesystemencoding()).encode('utf-8')
上面代碼先將字符串解碼成unicode編碼,再編碼成utf-8
3、列表或字典中的中文處理
data = {"a":"hello","b":"中國"} #假設是utf-8的格式
這時我們用print直接輸出data, 或用str函數將data轉為字符串。其中的中文是變成unicode的字符,如:
>>> data = {"a":"hello","b":"中國"}
>>> print data
{'a': 'hello', 'b': '\xd6\xd0\xb9\xfa'}
單獨輸出中文字段沒問題,如
>>> print data['b']
中國
如果希望能正常的將整個字典輸出,可以利用json包的dump方法,如:
>>> data = {"a":"hello","b":"中國"}
>>> s = json.dumps(data,ensure_ascii=False);
>>> print s
{"a": "hello", "b": "中國"}
>>> print isinstance(s,str)
True
4、當我們利用os的相關方法時,傳入的字符串編碼需要與系統一致,如:
filename = "D:/測試.txt"; # 假設是utf-8的格式
filename = filename.decode("utf-8").encode(sys.getfilesystemencoding()); #轉為當前系統字符集
re = os.path.exists(filename) # 檢查文件是否存在,必須要上面的先轉換為當前系統字符集才會正確
filename = filename.decode(sys.getfilesystemencoding()).encode("utf-8"); #重新轉為utf-8