小米air13.3内存条:Cygwin 1.7版 中文问题的解决(99%) | Go4Pro.org

来源:百度文库 编辑:偶看新闻 时间:2024/04/30 19:59:27

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中,赫然写着

To always have a valid string, use the UTF-8 charset by setting the environment variable $LANG, $LC_ALL, or $LC_CTYPE to a valid POSIX value

以及

A lot of character sets are supported now via a call to setlocale().
The setting of the environment variables $LANG, $LC_ALL or $LC_CTYPE will be used.

于是兴冲冲的在命令行下输入: set LC_ALL=zh_CN.GBK,然后再输入 ls,熟悉的中文文件名终于出现在了眼前。真简单,不是么?

在第一个胜利的鼓舞下,我再接再厉,设置好LC_ALL之后输入python,然后尝试在一个中文路径中 import os; print os.getcwd() ,果不其然,我得到了…………一堆乱码 囧。

为什么locale对python程序无效呢?难道python有特别的设置?再找资料,在python的locale module一节看到了一段话:

Initially, when a program is started, the locale is the C locale, no matter what the user’s preferred locale is. The program must explicitly say that it wants the user’s preferred locale settings by calling setlocale(LC_ALL, '').

翻译过来就是,当一个程序启动的时候,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 codecssys.stdout = codecs.getreader(locale.getpreferredencoding())(sys.stdout)sys.stdin = codecs.getreader(locale.getpreferredencoding())(sys.stdin)

这样一来,就可以正常输出程序中书写的中文信息,而无需任何特殊转换了。

经过这样一番努力,基本上解决我99%的问题:cygwin的工具可以正常使用中文、python可以正常使用中文,异常信息中的中文也可以正常输出。现在唯一没有解决的就是,当异常没有被捕获时,traceback的输出信息里,中文路径依然是乱码,似乎没有被locale设定所控制。不过因为这一点并不影响我的使用,暂时先不管了。

总结一下,在cygwin以及cygwin python中正常使用中文的做法:

  • 在“我的电脑”点右键,属性,高级,环境变量。增加一个环境变量 LC_ALL,值是zh_CN.GBK
  • 打开命令行,这时cgywin的工具应该都可以正常使用了。
  • 在我们的python程序开头增加这样一段代码:
#set locale environmentimport localeimport codecslocale.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中的。

Tags: cygwin, encoding, Python, 中文

收录于System