04 Aug 09 Cygwin 1.7版 中文問題的解決(99%)by 令狐蟲Linux玩久了之后,在Windows下用不了很多優(yōu)秀的命令行工具,就會感覺特別不爽。因此我一般都會在電腦上安裝一套GNU utils for windows。最開始的時候,我用的是minGW里的utils,但是它附帶的工具不全,雖然有一部分其他工具可以在其他地方google到,畢竟比較費神費力。 后來好好玩了一下Cygwin,開始喜歡上這個玩意兒了。以前一直以為cygwin就是開始菜單里啟動的那個bash界面,后來發(fā)現(xiàn)其實不是,cygwin實際上是通過一個cygwin1.dll實現(xiàn)了幾乎全部的UNIX函數(shù),因此只要鏈接到這個dll,就可以很方便的port各種UNIX工具了。port出來的工具,也可以在DOS命令行下正常執(zhí)行。 因為Cygwin的安裝是集中式的,有點類似于apt機制,這很方便,不需要到處找各種各樣的port了,只要從registry里安裝就行。 于是我將絕大部分的命令行工具都通過cygwin安裝使用,然后在PATH里填上cygwin/bin的路徑就行了,非常方便。包括原來在Windows下單獨安裝的python、hg等工具,都換成了cygwin版本的。 但是最近在做一個工作上用的數(shù)據(jù)導入工具的時候,麻煩來了。 因為導入文件有可能是中文文件名,或者存在于中文路徑中,我發(fā)現(xiàn)一旦涉及中文,cygwin版的python輸出就是亂碼,后來進一步發(fā)現(xiàn),python里直接輸出的中文也是有問題的。 然后,我聯(lián)想到使用cygwin命令的時候,對中文的處理也是不盡人意的,比如ls如果碰到中文文件名,就會輸出成一堆問號。 這次我想干脆將這些問題一起搞定。 于是就開始了找資料之旅。 網(wǎng)上很多處理cygwin中文的資料,都是針對bash的,然而我對cygwin的使用,在絕大部分情況下都不涉及bash。因此肯定要尋求其他途徑。 然后又找到一個日本人改造的cygwin的utf8版。這個倒是有用,不過他做的是1.5版的cygwin,而我現(xiàn)在使用的是1.7beta版的。降級,這個事情我可有點不甘愿。先放著吧,實在不行再采取這個方案。 google了一大圈無果,今天突然想起來去cygwin的官方網(wǎng)站瞧瞧。沒想到這一瞧還真有收獲,在1.7版的new feature中,赫然寫著
以及
于是興沖沖的在命令行下輸入: set LC_ALL=zh_CN.GBK,然后再輸入 ls,熟悉的中文文件名終于出現(xiàn)在了眼前。真簡單,不是么? 在第一個勝利的鼓舞下,我再接再厲,設置好LC_ALL之后輸入python,然后嘗試在一個中文路徑中 import os; print os.getcwd() ,果不其然,我得到了…………一堆亂碼 囧。 為什么locale對python程序無效呢?難道python有特別的設置?再找資料,在python的locale module一節(jié)看到了一段話:
翻譯過來就是,當一個程序啟動的時候,locale一定會被設置成C,無論你在環(huán)境里的設置是什么。如果需要使用環(huán)境設置,你必須顯式的調(diào)用 locale.setlocale(locale.LC_ALL, ”) 好吧,在我的程序里加上這一句,果然,中文路徑的輸出結果正常了。但是……,在程序里主動輸出的信息仍然是亂碼。而且當發(fā)生異常時,異常信息也是亂碼。 經(jīng)過一段胡折瞎騰,終于發(fā)現(xiàn),當locale設置成zh_CN.GBK時,要將輸出信息編碼成UTF-8,輸出才不會亂碼??墒?#8230;…,如果真這么改的話,用windows版的python運行時,信息又變成亂碼了。我不能寫這種跟運行環(huán)境相關的代碼啊,畢竟像我這樣用cygwin python的變態(tài)不會太多的。 于是繼續(xù)找資料,直覺告訴我這個問題應該跟stdout的encoding有關,于是找這幾個關鍵字:stdout、encode、codecs。經(jīng)過一番努力,還真的找到了結果:我們可以根據(jù)locale來設定stdout的encoding: import codecs sys.stdout = codecs.getreader(locale.getpreferredencoding())(sys.stdout) sys.stdin = codecs.getreader(locale.getpreferredencoding())(sys.stdin) 這樣一來,就可以正常輸出程序中書寫的中文信息,而無需任何特殊轉(zhuǎn)換了。 經(jīng)過這樣一番努力,基本上解決我99%的問題:cygwin的工具可以正常使用中文、python可以正常使用中文,異常信息中的中文也可以正常輸出?,F(xiàn)在唯一沒有解決的就是,當異常沒有被捕獲時,traceback的輸出信息里,中文路徑依然是亂碼,似乎沒有被locale設定所控制。不過因為這一點并不影響我的使用,暫時先不管了。 總結一下,在cygwin以及cygwin python中正常使用中文的做法:
#set locale environment import locale import codecs locale.setlocale(locale.LC_ALL, '') #將環(huán)境中的locale設定沿用到python程序中 sys.stdout = codecs.getreader(locale.getpreferredencoding())(sys.stdout) sys.stdin = codecs.getreader(locale.getpreferredencoding())(sys.stdin) #根據(jù)locale設置指定標準輸入輸出的編碼 這樣可以使得程序在native python和cygwin python中都沒有中文問題(99%的情況下)。 另外要注意一點的是,在python程序中,對locale的改變請務必放在主程序中而不要放在module中,否則可能會造成module和主程序的locale設定混亂,引起不可預期的問題。在主程序中對locale的設定會自動沿用到各個module中的。 |
|