使用Python2处理中文的时候可能会遇到过这样的问题
SyntaxError: Non-ASCII character '\xe4' in file play.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
其中我的代码是这样的
sentence = '你好'
错误信息提示这一行代码中含有非ASCII字符,并且对于这些字符No encoding declared
.从错误信息可以看出来Python2默认的编码方式是ASCII。要使用中文需要告诉解释器编码方式是UTF-8。方法是在文件的开头加上# -*- coding: utf-8 -*-
.
接下来我又加了一行,目的是想输出句子的长度
sentence = '你好'
print(len(sentence))
此时运行脚本输出的结果是6,而不是2。这其实就涉及到另一个问题,Python2中字符串的存储形式。在Python2中,字符串通常用str
或unicode
两种方式来存储,两者都是basestring
的子类。在声明时,类似s='abc'
得到的就是str
类型的字符串,而s=u'abc'
得到的就是unicode
类型的字符串。在Python2的内置方法和很多库当中,都是针对unicode
来进行操作的。所以在我们的例子中,sentence
变量作为一个str
类型传给len()
,返回结果不是预想中的2。
为了调用Python2中的函数来处理字符串,我们需要实现将str
类型的字符串转换成unicode
,借助的工具是encode/decode
函数。在我们的例子中,进行如下操作
sentence = '你好'
sentence = sentence.decode('utf-8')
print(len(sentence))
运行脚本将会输出2.
如果想将unicode
类型转回str
类型,执行sentence=sentence.encode('utf-8')
即可。或者希望编码成其他形式,比如gbk
,gb2312
,只需要修改编码参数就可以了。
如果我们直接在解释器中操作,会得到以下结果
>>> s = '中文'
>>> s
'\xe4\xb8\xad\xe6\x96\x87'
>>> s = s.decode('utf-8')
>>> s
u'\u4e2d\u6587'
>>> print(s)
中文
为什么s
在decode
成为unicode
之后print(s)
还会正常输出呢,这是因为在打印到控制台的时候回自动将unicode
编码成控制台支持的编码方式。如果我们人为将其编码方式设置为gbk
,将会产生下面的效果
>>> s = s.encode('gbk')
>>> s
'\xd6\xd0\xce\xc4'
>>> print(s)
����
控制台输出了乱码,这是因为s
被编码为了gbk
格式的,而控制台支持的是utf-8
编码。
那么我们其实可以发现,decode/encode
配合使用可以实现str
编码方式的转变。其实还有一种更简单的方法,直接对str
进行encode
# -*- coding: utf-8 -*-
s = '中文'
s = s.encode('gbk')
其实这样做运行起来是会报错的
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
原因是这样的,直接调用str
类型的encode
函数,它会隐式的首先按照当前的默认编码方式来decode
到unicode
,然后在encode
到指定的编码方式。报错的原因是,默认的编码方式是ascii
,无法解析中文。这里的编码和文件头部指定的编码是不一样的,为了不报错,还需要加入
reload(sys)
sys.setdefaultencoding('utf-8')
这样一来代码就可以正常运行了。介绍这一段的目的是,我在网络上看到好多介绍使用sys.setdefaultencoding('utf-8')
来解决编码问题的文章,但是都没有讲清楚他的作用,让人把这两行代码的作用和在文件头部指定# -*- coding: utf-8 -*-
混淆了。其实在一般情况下还是最好显示的写sentence.decode(...).encode(...)
的形式,这样就不涉及sys
当前的默认编码了。
本文长期更新,如果我再踩到Python2中编码的坑还会在这里和大家分享 :)