Python中文全攻略

原創文章,轉載請註明出處。
python


 1.        在Python中使用中文mysql

在Python中有兩種默認的字符串:str和unicode。在Python中必定要注意區分「Unicode字符串」和「unicode對象」的區別。後面全部的「unicode字符串」指的都是python裏的「unicode對象」。
事實上在Python中並無「Unicode字符串」這樣的東西,只有「unicode」對象。一個傳統意義上的unicode字符串徹底能夠用str對象表示。只是這時候它僅僅是一個字節流,除非解碼爲unicode對象,沒有任何實際的意義。
咱們用「哈哈」在多個平臺上測試,其中「哈」對應的不一樣編碼是:
1.              UNICODE (UTF8-16),      C854
2.              UTF-8,                    E59388
3.              GBK,               B9FE
1.1     Windows控制檯
下面是在windows控制檯的運行結果:
能夠看出在控制檯,中文字符的編碼是GBK而不是UTF-16。將字符串s(GBK編碼)使用decode進行解碼後,能夠獲得同等的unicode對象。
注意:能夠在控制檯打印ss並不表明它能夠直接被序列化,好比:
向文件直接輸出ss會拋出一樣的異常。在處理unicode中文字符串的時候,必須首先對它調用encode函數,轉換成其它編碼輸出。這一點對各個環境都同樣。
總結:在Python中,「str」對象就是一個字節數組,至於裏面的內容是否是一個合法的字符串,以及這個字符串採用什麼編碼(gbk, utf-8, unicode)都不重要。這些內容須要用戶本身記錄和判斷。這些的限制也一樣適用於「unicode」對象。要記住「unicode」對象中的內容可絕對不必定就是合法的unicode字符串,咱們很快就會看到這種狀況。
總結:在windows的控制檯上,支持gbk編碼的str對象和unicode編碼的unicode對象。
1.2     Windows IDLE(在Shell上運行)
在windows下的IDLE中,運行效果和windows控制檯不徹底一致:
能夠看出,對於不使用「u」做標識的字符串,IDLE把其中的中文字符進行GBK編碼。可是對於使用「u」的unicode字符串,IDLE竟然同樣是用了GBK編碼,不一樣的是,這時候每個字符都是unicode(對象)字符!!此時len(ss) = 4。
這樣產生了一個神奇的問題,如今的ss沒法在IDLE中正常顯示。並且我也沒有辦法把ss轉換成正常的編碼!好比採用下面的方法:
這有多是由於IDLE本地化作得不夠好,對中文的支持有問題。建議在IDLE的SHELL中,不要使用u「中文」這種方式,由於這樣獲得的並非你想要的東西。
這同時說明IDLE的Shell支持兩種格式的中文字符串:GBK編碼的「str」對象,和UNICODE編碼的unicode對象。
1.3     在IDLE上運行代碼
在IDLE的SHELL上運行文件,獲得的又是不一樣的結果。文件的內容是:
直接運行的結果是:
毫無瑕疵,至關使人滿意。我沒有試過其它編碼的文件是否能正常運行,但想來應該是不錯的。
一樣的代碼在windows的控制檯試演過,也沒有任何問題。
1.4     Windows Eclipse
在Eclipse中處理中文更加困難,由於在Eclipse中,編寫代碼和運行代碼屬於不一樣的窗口,並且他們能夠有不一樣的默認編碼。對於以下代碼:
#!/usr/bin/python
# -*- coding: utf-8 -*-
 
s = "哈哈"
ss = u'哈哈'
 
print repr(s)
print repr(ss)
 
print s.decode('utf-8').encode('gbk')
print ss.encode('gbk')
 
print s.decode('utf-8')
print ss
 
前四個print運行正常,最後兩個print都會拋出異常:
'/xe5/x93/x88/xe5/x93/x88'
u'/u54c8/u54c8'
哈哈
哈哈
Traceback (most recent call last):
 File "E:/Workspace/Eclipse/TestPython/Test/test_encoding_2.py", line 13, in <module>
    print s.decode('utf-8')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
也就是說,GBK編碼的str對象能夠正常打印,可是不能打印UNICODE編碼的unicode對象。在源文件上點擊「Run as」「Run」,而後在彈出對話框中選擇「Common」:
能夠看出Eclipse控制檯的缺省編碼方式是GBK;因此不支持UNICODE也在情理之中。若是把文件中的coding修改爲GBK,則能夠直接打印GBK編碼的str對象,好比s。
若是把源文件的編碼設置成「UTF-8」,把控制檯的編碼也設置成「UTF-8」,按道理說打印的時候應該沒有問題。可是實驗代表,在打印UTF-8編碼的str對象時,中文的最後一個字符會顯示成亂碼,沒法正常閱讀。不過我已經很知足了,至少人家沒有拋異常不是:)
BTW: 使用的Eclipse版本是3.2.1。
1.5     從文件讀取中文
在window下面用記事本編輯文件的時候,若是保存爲UNICODE或UTF-8,分別會在文件的開頭加上兩個字節 「/xFF/xFE」 和三個字節「/xEF/xBB/xBF」。在讀取的時候就可能會遇到問題,可是不一樣的環境對這幾個多於字符的處理也不同。
以windows下的控制檯爲例,用記事本保存三個不一樣版本的「哈哈」。
 

打開utf-8格式的文件並讀取utf-8字符串後,解碼變成unicode對象。可是會把附加的三個字符一樣進行轉換,變成一個unicode字符,字符的數據值爲「/xFF/xFE」。這個字符不能被打印。編碼的時候須要跳過這個字符。sql

打開unicode格式的文件後,獲得的字符串正確。這時候適用utf-16解碼,能獲得正確的unicdoe對象,能夠直接使用。多餘的那個填充字符在進行轉換時會被過濾掉。
 
打開ansi格式的文件後,沒有填充字符,能夠直接使用。
結論:讀寫使用python生成的文件沒有任何問題,可是在處理由notepad生成的文本文件時,若是該文件多是非ansi編碼,須要考慮如何處理填充字符。
1.6     在數據庫中使用中文
剛剛接觸Python,我用的數據庫是mysql。在執行插入、查找等操做時,若是運行環境使用的字符編碼和mysql不一致,就可能致使運行時的錯誤。固然,和上面看到的狀況同樣,運行環境並非關鍵因素,關鍵是查詢語句的編碼方式。若是在每次執行查詢操做時都把查詢字符串作一次編碼轉換,轉變成mysql的默認字符編碼,同樣不會遇到問題。可是這樣寫代碼也太痛苦了吧。
使用以下代碼鏈接數據庫:
self.conn = MySQLdb.connect(use_unicode = 1, charset='utf8', **server)
我不能理解的是既然數據庫用的默認編碼是UTF-8,我鏈接的時候也用的是UTF-8,爲何查詢獲得的文本內容倒是UNICODE編碼(unicode對象)?這是MySQLdb庫的設置麼?
1.7     在XML中使用中文
使用xml.dom.minidom和MySQLdb相似,對生成的dom對象調用toxml方法獲得的是unicode對象。若是但願輸出utf-8文本,有兩種方法:
1.使用系統函數
在輸出xml文檔的時候進行編碼,這是我以爲最好的方法。
xmldoc.toxml(encoding=’utf-8’)
xmldoc.writexml(outfile, encoding = ‘utf-8’)
2.本身編碼生成
在使用toxml以後能夠調用encode方法對文檔進行編碼。但這種方法沒法獲得合適的xml declaration(xml文檔第一行中的encoding部分)。
不要嘗試經過xmldoc.createProcessingInstruction來建立一個processing instraction:
<?xml version=’1.0’ encoding=’utf-8’?>
xml declaration雖然看起來像是,可是事實上並非一個processing instraction。能夠通下面的方法獲得一個滿意的xml文件:
print >> outfile, 「<?xml version=’1.0’ encoding=’utf-8’?>」
print >> outfile, xmldoc.toxml().encode(‘utf-8’)[22:]
其中第二行須要過濾掉在調用xmldoc.toxml時生成的「<?xml version=’1.0’ ?>」,它的長度是22。
 
相面是兩種方法的用法比較:
 
另外,在IDLE的shell中,不要用 u’中文’ 對屬性進行賦值。上面討論過,這樣獲得的unicode字符串不正確。