python采用的编码
目录
一、背景知识
二、python之中的编码
1、文件本身的编码
我们使用编辑器编辑python文件的时候,可以选择编码格式,
比如notepad++,就可以选择ascii、utf8、utf16、ucs2、gbk等编码格式。
选择这些编码格式之后,保存python文件,这个时候python文件的编码格式就确定了。在此之后,如果想转换文件的编码格式,可以使用notepad++进行相应的编码转换,例如,现在编码格式是ucs2,我在编辑器中选择utf8编码格式,然后保存,那么文件就会变成utf8格式。当然,也可以转换为ASCII的格式,只不过可能很多字符就是乱码了。
python解释器能否自动识别文件的编码格式?
我们来做一个小小的测试:
第一步:用Notepad++创建一个utf8的无bom文件,test.py
print "你好世界"
保存好。
第二步:用python2.7执行该文件(注意,我们没有在该文件开头声明文件编码)
python test.py
然后,boom,出错了。
这是由于python2.7默认使用ASCII码去解析python文件内容,遇到了utf8的字符,自然就识别不了,然后出错了。
那么为什么可以识别英文字符,而识别不了中文字符呢?
因为utf-8的英文字符和ASCII码的英文字符码值是一样的。具体参考开头的连接内容。背景知识
二、python如何识别文件编码格式?
方法一:使用#_*_ coding: utf-8 _*_
# -*- coding: utf-8 -*-
print "你好世界"
这一行是告诉python解释器,使用utf8格式来解析文件中的内容。
执行结果:
方法二:如下所示
#_*_ encoding: utf-8 _*_
import sys
reload(sys)
sys.setdefaultencoding('utf-8') #设置默认的编码格式为utf-8
print "你好世界"
执行结果:
三、字符串输入输出编码格式
str为字节码,会根据某种编码把字符串转成一个个字节,这个时候字符和字节没有所谓固定的一一对应的关系。
直接赋值字符串,类型为str,str为字节串,会按照开头的encoding来编码成一个个的字节。
1、encode和decoded的使用:
encode的正常使用:对unicode类型进行encode,得到字节串str类型。也即是unicode -> encode(根据指定编码) -> str。
decode的正常使用:对str类型进行decode,得到unicode类型。也即是str -> decode(根据指定编码) -> unicode。
python中的Unicode是utf16,也就是双字节形式的unicode。
注意:encode和decode的时候都是需要指定编码的。
因为在编码的时候要知道原来的编码是什么和按照什么新编码方式进行编码,要用到两种编码,这里默认有一个unicode,所以需要再指定一个编码方式。解码的时候也是一个道理。
这两个方法就是在unicode和str之间用指定编码进行转换。
s3 = u'统一码'.encode('utf8') #python2中,中文必须加u前缀,否则就会不正常。
print type(s3) # 输出 <type 'str'>
s4 = '字节串'.decode('utf8')
print type(s4) #输出 <type 'unicode'>
encode的不正常使用:对str类型进行encode,因为encode需要的是unicode类型,这个时候python会用默认的系统编码decode成unicode类型,再用你给出编码进行encode。(注意这里的系统编码不是开头的encoding,具体例子见下文第5点)
decode的不正常使用:对unicode类型进行decode,python会用默认的系统编码encode成str类型,再用你给出的编码进行decode。
所以改好对应的系统默认编码,就算不正常使用,也不会报错啦。不过多拐了一下路,个人不喜欢这样。
系统编码的修改:
系统默认使用ascii编码,需要进行相应的修改。(python2中默认使用ASCII,python3默认使用utf-8了)
这个编码和开头的encoding不同之处在于,开头的encoding是对于文件内容的编码。
这里的编码是一些python方法中默认使用的编码,比如对str进行encode的时候默认先decode的编码,比如文件写操作write的encode的编码。
import sys
reload(sys)
sys.setdefaultencoding('utf8')
s = '字节串str'
s.encode('utf8')
#等价于
s.decode(系统编码).encode('utf8')
关于系统默认编码发挥作用的地方,来看看另一个例子。
import sys
print sys.getdefaultencoding() # 输出ascii
s = 'u华南理工大学'
print s[-2:] == '大学' # 返回False,并有warning提醒
reload(sys)
sys.setdefaultencoding('utf8')
print s[-2:] == '大学' # 返回True
根据结果得知:python在用==比较时,如果第一个操作符是unicode而第二个不是的话,会自动用系统默认编码帮第二个操作符decode。
PS:为什么需要reload(sys)呢。首先,reload是用于重新加载之前import的模块。
这里需要重新加载sys的原因是:python在加载模块时候删除了sys中的setdefaultencoding方法(可能是出于安全起见),所以需要reload这个sys模块。
2、文件的字符串输入和输出编码
查看文件的编码
import chardet
f = open('a.doc',r)
data = f.read()
print chardet.detect(data)
文件读写
首先要记住,读出和写入,这两个文件的关口都是用str类型的,就是一个个字节。
python中内置的默认open在读取文件的时候以字节串str的形式,读出一个个字节。读取后要用正确的编码才能decode成正确的unicode,所以要知道原来在文件中的编码。
写文件的时候也是一个道理,用str类型,以字节的形式写入,这个str是以某种编码方式编码的,要注意用正确的编码方式编码,一般是按utf8编码后写文件。
如果你用unicode类型写入,python会根据系统默认编码来把unicode编码成str再写入文件。因为写入文件需要的是str,是str就写,不是我就把你转成str再写。
简单原则,尽量用str写入,避免使用默认编码,这样也不用在开头修改默认编码。
python中模块codecs中的open方法可以指定一个编码。它保证了读入和写出的字节都是按照这个指定编码进行编码的。
这样在读文件的时候:会把读出的str按照指定编码decode成unicode。
写文件的时候:如果是unicode,会根据指定编码encode成str然后写入;如果是str,会根据系统默认编码把str进行decode得到unicode,再根据指定编码encode成str进行写入。
简单原则,尽量用unicode写入,避免使用默认编码,这样也不用在开头修改默认编码。
注意一下,对于其它方式读写文件,需要自行debugger看看编码的问题。比如我在python中读取excel的时候读出来就直接是unicode而不是str。
总结:
设置相应的默认编码为utf8;
读文件拿到str类型:str -> decode('utf8') -> unicode
程序处理:最好统一用unicode以简化处理
写文件:unicode -> encode('utf8') -> str,用str类型写入文件
当然前提是文件都是utf8格式的啦,包括源文件和读写的数据文件。