04 Aug 09 Cygwin 1.7版 中文问题的解决(99%)by 令狐虫Linux玩久了之后,在Windows下用不了很多优秀的命令行工具,就会感觉特别不爽。因此我一般都会在电脑上安装一套GNU utils for windows。最开始的时候,我用的是minGW里的utils,但是它附带的工具不全,虽然有一部分其他工具可以在其他地方google到,毕竟比较费神费力。 后来好好玩了一下Cygwin,开始喜欢上这个玩意儿了。以前一直以为cygwin就是开始菜单里启动的那个bash界面,后来发现其实不是,cygwin实际上是通过一个cygwin1.dll实现了几乎全部的UNIX函数,因此只要链接到这个dll,就可以很方便的port各种UNIX工具了。port出来的工具,也可以在DOS命令行下正常执行。 因为Cygwin的安装是集中式的,有点类似于apt机制,这很方便,不需要到处找各种各样的port了,只要从registry里安装就行。 于是我将绝大部分的命令行工具都通过cygwin安装使用,然后在PATH里填上cygwin/bin的路径就行了,非常方便。包括原来在Windows下单独安装的python、hg等工具,都换成了cygwin版本的。 但是最近在做一个工作上用的数据导入工具的时候,麻烦来了。 因为导入文件有可能是中文文件名,或者存在于中文路径中,我发现一旦涉及中文,cygwin版的python输出就是乱码,后来进一步发现,python里直接输出的中文也是有问题的。 然后,我联想到使用cygwin命令的时候,对中文的处理也是不尽人意的,比如ls如果碰到中文文件名,就会输出成一堆问号。 这次我想干脆将这些问题一起搞定。 于是就开始了找资料之旅。 网上很多处理cygwin中文的资料,都是针对bash的,然而我对cygwin的使用,在绝大部分情况下都不涉及bash。因此肯定要寻求其他途径。 然后又找到一个日本人改造的cygwin的utf8版。这个倒是有用,不过他做的是1.5版的cygwin,而我现在使用的是1.7beta版的。降级,这个事情我可有点不甘愿。先放着吧,实在不行再采取这个方案。 google了一大圈无果,今天突然想起来去cygwin的官方网站瞧瞧。没想到这一瞧还真有收获,在1.7版的new feature中,赫然写着
以及
于是兴冲冲的在命令行下输入: set LC_ALL=zh_CN.GBK,然后再输入 ls,熟悉的中文文件名终于出现在了眼前。真简单,不是么? 在第一个胜利的鼓舞下,我再接再厉,设置好LC_ALL之后输入python,然后尝试在一个中文路径中 import os; print os.getcwd() ,果不其然,我得到了…………一堆乱码 囧。 为什么locale对python程序无效呢?难道python有特别的设置?再找资料,在python的locale module一节看到了一段话:
翻译过来就是,当一个程序启动的时候,locale一定会被设置成C,无论你在环境里的设置是什么。如果需要使用环境设置,你必须显式的调用 locale.setlocale(locale.LC_ALL, ”) 好吧,在我的程序里加上这一句,果然,中文路径的输出结果正常了。但是……,在程序里主动输出的信息仍然是乱码。而且当发生异常时,异常信息也是乱码。 经过一段胡折瞎腾,终于发现,当locale设置成zh_CN.GBK时,要将输出信息编码成UTF-8,输出才不会乱码。可是……,如果真这么改的话,用windows版的python运行时,信息又变成乱码了。我不能写这种跟运行环境相关的代码啊,毕竟像我这样用cygwin python的变态不会太多的。 于是继续找资料,直觉告诉我这个问题应该跟stdout的encoding有关,于是找这几个关键字:stdout、encode、codecs。经过一番努力,还真的找到了结果:我们可以根据locale来设定stdout的encoding: import codecs sys.stdout = codecs.getreader(locale.getpreferredencoding())(sys.stdout) sys.stdin = codecs.getreader(locale.getpreferredencoding())(sys.stdin) 这样一来,就可以正常输出程序中书写的中文信息,而无需任何特殊转换了。 经过这样一番努力,基本上解决我99%的问题:cygwin的工具可以正常使用中文、python可以正常使用中文,异常信息中的中文也可以正常输出。现在唯一没有解决的就是,当异常没有被捕获时,traceback的输出信息里,中文路径依然是乱码,似乎没有被locale设定所控制。不过因为这一点并不影响我的使用,暂时先不管了。 总结一下,在cygwin以及cygwin python中正常使用中文的做法:
#set locale environment import locale import codecs locale.setlocale(locale.LC_ALL, '') #将环境中的locale设定沿用到python程序中 sys.stdout = codecs.getreader(locale.getpreferredencoding())(sys.stdout) sys.stdin = codecs.getreader(locale.getpreferredencoding())(sys.stdin) #根据locale设置指定标准输入输出的编码 这样可以使得程序在native python和cygwin python中都没有中文问题(99%的情况下)。 另外要注意一点的是,在python程序中,对locale的改变请务必放在主程序中而不要放在module中,否则可能会造成module和主程序的locale设定混乱,引起不可预期的问题。在主程序中对locale的设定会自动沿用到各个module中的。 |
|