您的位置:首页 > 编程语言 > Python开发

python 中文编码 问题

2010-12-03 16:05 567 查看
http://blog.csdn.net/bttsyy/archive/2010/10/23/5961019.aspx

这段时间为了项目开发的编译需要,也为了以后的自动化构建系统的需要,我们工作室申请了一台四核的服务器,专门完成一些自动化编译的工作,而我就主动要求承担这份工作,一来我对拓展自己的技术领域比较看重,二来确实也只有我适合,因为之前有过脚本构建的经验,正好也借此机会加强一下自己的python开发能力。

开发采用python2.5版本,使用pysvn进行svn的操作,使用webpy搭建简易的web编译页面,采用incredbuild命令行执行分布式编译。
整个过程的学习不算特别困难,python对于各种开发工具的支持还是非常方便的,唯一不爽的是不管是pysvn还是webpy,文档都是非常的简洁甚至可以说是简陋,大部分都需要自己试验,或者有过丰富经验,才能应用熟练。

直到所有的工作都搞定了,最后发现了一个字符编码的问题,本文简单记录下问题和解决方案,为这方面的新手铺铺路,也欢迎高手给予指点。
问题是这样的:首先我在浏览器页面的表单上输入中文的svn的log,通过webpy的server接收到这个输入,然后通过参数传给编译脚本,执行编译,目录复制和svn提交,虽然页面最后的反馈,svnlog是正常显示的,但是通过svn更新下来的目录,log信息都是乱码,而tortoise则更是无法显示。
问题其实很显然,编码的问题。关于编码的种类和国际国家标准,这里就不多做讲解了,直接Google是更好的办法。首先搞清楚每个阶段的编码都采用了什么标准。直观点讲,直接用python的print repr(str)就可以了。如果是u'/u****/u****'就是unicode,如果是'/x**/x**',一般都是utf8或者gbk或者mbcs。测试代码和结果如下:

strcode_test.py内容:
# coding=utf-8

uni_str = u'编译机测试'

print 'unicode: ',repr(uni_str)

print 'utf-8: ',repr(uni_str.encode('utf-8'))

print 'gbk: ',repr(uni_str.encode('gbk'))

print 'mbcs: ',repr(uni_str.encode('mbcs'))

执行输出:
unicode: u'/u7f16/u8bd1/u673a/u6d4b/u8bd5'

utf-8: '/xe7/xbc/x96/xe8/xaf/x91/xe6/x9c/xba/xe6/xb5/x8b/xe8/xaf/x95'

gbk: '/xb1/xe0/xd2/xeb/xbb/xfa/xb2/xe2/xca/xd4'

mbcs: '/xb1/xe0/xd2/xeb/xbb/xfa/xb2/xe2/xca/xd4'

#插播:
很多文章都有对python的字符编码做过详细的讲解,但是我注意到他们往往都忽略了一个细节,这些对于python老手也许算不上什么,但对于新手或者对编码不甚了解的程序员可能造成困扰,这里先解释一个细节:
python对于py文件中的中文的编码解释依赖于文件本身的编码,比如你在文件开头指定了
# coding=utf-8
这里只是告诉python解释器本文件是utf-8编码的,但是文件本身的编码却可能根本不是utf-8的,这取决于你的编辑器和你的系统如果保存它,所以如果两者编码不一致,那么对于py文件中出现的中文,很可能就会出问题,比如你存了ANSI格式,结果python按照utf-8解释中文,一定是乱套的。所以,一定要保证文件头指定和文件编码格式的一致!
#插播结束

通过打印编码,我可以检测到在webpy的server端,我接收到的是unicode的字符串,与页面编码无关,看得出webpy已经做了兼容性的处理,统一为unicode编码。简单代码如下:
代码段1:
1:build_info = web.input()
2:build_str = '***' if condition1 else build_info.info1
3:build_str += '***' if condition2 else build_inof.info2
4:build_str + = '/log %s' % build_info.svnlog
通过上面的代码,我将编译脚本(smart_build.py)的参数用build_str存储起来,然后通过下面的代码进行调用。
代码段2:
1:cmd = 'smart_build.py %s' % build_str
2:subprocess.Popen(cmd,shell=True)
在smart_build.py中处理svn提交的代码如下:
代码段3:
1:svn_log = arg_list[*]
2:svn_client.checkin(dir,svn_log)

接下来一个个解释遇到的问题:
问题1:
就如上面所写,会在代码段2中的line2出错,提示:'ascii' codec can't encode characters in position 46-50:ordinal not range(128)。
解释1:
此时打印cmd可以看到这是一个unicode字符串,这问题可以解释为python2.5中的subprocess在处理windows命令行输入时是按照本机编码来进行解释(中文操作系统一般都是gbk,此处显示ascii应该是系统无法分辨中英文,所以用ascii进行提示),所以unicode字符串无法被正常解释。
解决1:
代码段2:line2:改为subprocess.Popen(cmd.encode('gbk'),shell=True)

插曲1:
我一开始以为是svnlog的中文编码问题,所以将代码段1的line4改成svnlog.encode('gbk'),这时又会遇到另一个问题,
问题1.1
line4直接报错:'ascii' codec can't decode byte 0xb1 in position 0:ordinal not range(128)
解释1.1:
line2和line3中,如果执行了build_str+inof1(info2),那么build_str就转换成了unicode编码,这时再执行build_str += svnlog.encode('gbk'),那么对于svnlog就要按照unicode解释,由于unicode和gbk的不兼容造成解释失败。
解决1.1:
可以全过程采用gbk编码,但是不如解决1来得简单。

问题2:
解决了问题1之后,代码走到了代码段3,代码正常执行,没问题,出问题的是svn版本库上的log,会发现只要是中文就是乱码。
解释2:
我们在Windows系统的控制台中使用svn ci的时候,理论上-m "编译机测试"也是通过gbk编码的,却也可以正常显示,但这里为什么出现乱码呢?我做了几组测试,对比svn ci -m "**" --encoding unicode/utf-8/gbk,得出结论是svn在提交log时统一将日志重新编码成utf-8发送给服务器,svn ci -m "编译机测试"执行时,默认按照gbk编码解释log,所以没问题,而pysvn的checkin就比较奇特,unicode和utf-8都可以正常显示,但是gbk就不行,没看过源代码,不过应该是内部做了一个编码的检测处理,让ci命令最终可以得到正确的字符编码,有空我还要看下源码确认下。
解决2:
代码段3:line1: svn_log = arg_list[*].encode('gbk')

附注:
由于本应用只是为了解决实际的编译系统的问题,所以在中文编码多采用gbk,其实采用mbcs是一种更国际化的做法,所以,在国际开发的时候,多使用mbcs是更保险的做法,具体mbcs的应用可以Google一下:-)

到此为止,整个系统可以正常工作了,通过这次我对于不同应用之间的编码问题有了更好的把握,也期待有一天可以有一种大同的方式解决世界上所有字符编码,unicode是一种很好的方式,希望能够得到更好的推广和普及。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: