python 中几个层次的中文编码
Minbin Jiang Lv4

介绍

一直不太喜欢使用命令行,所以去年年底的技术创新中,使用TkInter来开发小工具。结果花费了大量的时间来学习TkInter ui的使用。
最近想整理该工具,使用命令行的形式,然后将该工具做成exe的形式进行分发。在工作一开始就遇到了编码的问题。
在脚本中有如下代码,用来接收用户交互式输入的ip。

server = raw_input("请输GIS Server IP:")

在脚本文件的第一行,我已经加了如下代码

# -*-coding: utf-8 -*-

但是在windows 的控制台执行的时候,出现了乱码。有点不解,因为自己一直以来在python中,处理中文都是在文件头加入该代码。

通过搜索发现,是因为在windows cmd 默认的使用的cp936的编码。既然知道使用这种编码则将编码改为如下:

# -*-coding: cp936-*-

但是得到如下的错误:

SyntaxError: encoding problem: cp936 with BOM

百思不得其解。作为懒癌患者,就想绕过去。则采用如下方式,对单独字符串进行编码。

userName=raw_input("请输入站点管理员用户名:".decode("utf-8").encode("cp936"))

这样重要在cmd中可以正常的输出中文了。但是问题来了,我的脚本中,有上百行代码有中文。每个地方都这么写,感觉偷懒不成,反被*。
这个时候,通过搜索。逐步的发现了问题的原因。这是因为python有几个层次的编码。分别是:

  • 字符串变量级别编码
  • 脚本级别的编码
  • py文件级别的编码
  • 显示窗口的编码

字符串变量的编码

对单个字符串转码,可以使用:**encode()**编码成可以显示的。通常对字符串不能由一个编码直接转换为另一个编码。通常需要解码到Unicode,然后对unicode字符串重新的编码。比如上面的示例。

脚本的编码

上面通过设置 #coding:utf-8设置的就是脚本里面内容的编码。也就是该脚本文件中所有的字符串变量都采用该处设置的编码方式。
##py文件的编码
py文件的编码,默认的是ANSI。但是也可以使用utf-8,unicode编码。

显示窗口的编码

上面的几种情况,中文在运行阶段不会出错。但是这些中文还不一定能够正常的显示。能否正常的显示,还有显示窗口支持的编码决定。比如cmd中中文支持GBK和cp936,所以代码中的字符串需要编码到这两种才可以显示。
##测试

  1. 当py文件的编码为utf-8的时候。代码中唔需要添加#coding:utf-8 。脚本中的中文,在运行过程不会报错。
  2. 当py文件的编码为ANSI的时候。如代码中没有显示的添加 ** --coding:utf-8 -- **,则当代码中出现中文的时候,运行脚本的时候。会出现如下错误
    SyntaxError: Non-ASCII character '\xe4' in file
  3. 当py文件设置为utf-8,而显示设置代码编码为#coding:936。则会出现ncoding problem: cp936 with BOM的错。这个时候,将py文件的编码改为ANSI即可。

##结论
通过上面的测试,有几个结论:

  1. 编码有层次结构。文件编码影响脚本内容编码,脚本内容编码决定 其中的字符串编码。
  2. 当字符串显示设置了编码的时候。字符串的编码为显示设置的编码,此时文件和脚本编码不起作用。当字符串没有显示设置编码的时候,则采用上一级编码决定。
  3. 所以设置这三种编码的时候,需要确保三种编码之间能够转换。否则会出现上面列举的错误。