标签:
下面的文章和编码具体解释总结了常见字符编码后,这篇文章会对python中常见的编码问题进行分析和总结。因为python3.x版本号和python2.x版本号在字符编码方面有非常大差异,所以本文都是以Python2.7.5来分析2.x版本号中的字符编码问题。
python中有两种数据模型来支持字符串这样的数据类型,str和unicode,它们的基类都是basestring。
比方s = "中文"
就是str类型的字符串,而u=u"中文"
就是一个unicode类型的字符串。unicode是由str类型的字符串解码后得到。unicode也能够编码成str类型。即
str --> decode -->unicode unicode --> encode --> str
严格来说,str或许应该叫做字节串,由于对于UTF-8编码的str类型"中文",使用len()函数得到的结果是6,由于UTF-8编码的str类型“中文”
实际是"\xe4\xb8\xad\xe6\x96\x87"
。而对于unicode类型u“中文”(实际是
u"\u4e2d\u6587"
),使用len()函数得到结果是2.
在python源码文件里假设实用到非ascii字符,比方中文,那么须要在源码文件头部声明源码字符编码,格式例如以下:
#-*- coding: utf-8 -*-
这个格式看起比較复杂,事实上python仅仅检查#、coding,编码等字符串,能够简写成#coding:utf-8,甚至还能够写成#coding:u8。
文件头部编码声明决定了python解析源代码中的str的编码选择方式,比方头部声明的是utf-8编码,则代码中s="中文"
python就会依照utf-8编码格式来解析,通过repr(s)
能够看到字符编码是"\xe4\xb8\xad\xe6\x96\x87"
。假设头部声明的编码是gbk编码,则python会对s採用gbk编码解析。结果是"\xd6\xd0\xce\xc4"
。
须要注意的是,文件本身的编码要跟文件头部声明编码一致,不然就会出现故障。
文件本身的编码在Linux以下能够在vim下用命令set fenc
来查看。
假设文件本身编码是gbk。而源代码文件头部声明的编码是utf-8,这样假设源代码中有中文就会有问题了,由于本身中文str存储是依照gbk编码来的。而python在解析str的时候又以为是utf-8编码。这样就会报SyntaxError: (unicode error) ‘utf8‘ codec can‘t decode byte
错误。
以下看个python默认编码导致的问题:
#coding: utf-8 u = u"中文" print repr(u) # u'\u4e2d\u6587' s = "中文" print repr(s) # '\xe4\xb8\xad\xe6\x96\x87' u2 = s.decode("utf-8") print repr(u2) # u'\u4e2d\u6587' #s2 = u.decode("utf-8") #编码错误 #u2 = s.encode("utf-8") #解码错误
注意实例中凝视掉的2行代码,对于unicode最好不要直接调用decode。str最好不要直接调用encode方法。由于假设是直接调用。则相当于u.encode(default_encoding).decode("utf-8")
。default_encoding是python的unicode实现中用的默认编码,即sys.getdefaultencoding()
得到的编码,假设你没有设置过。那么默认编码就是ascii,假设你的unicode本身超出了ascii编码范围就会报错。同理,假设对str直接调用encode方法,那么默认会先对str进行解码。即s.decode(default_encoding).encode("utf-8"),假设str本身是中文,而default_encoding是ascii的话。解码就会出错,从而导致上面这两行会分别报UnicodeEncodeError: ‘ascii‘ codec can‘t encode characters in position...
错误和UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte 0xe4 in position...
错误。
上面样例中凝视掉的两行代码假设运行就会报错,当然,假设本身str或者unicode都在ascii编码范围。就没有问题。比方s = "abc"; s.encode("utf-8")
就不会有问题。语句运行后会返回一个跟s的id不同的str。
那假设要解决实例1中的问题,有两种方法,其一是明白指定编码,例如以下所看到的:
#coding: utf-8 u = u"中文" print repr(u) # u'\u4e2d\u6587' s = "中文" print repr(s) # '\xe4\xb8\xad\xe6\x96\x87' u2 = s.decode("utf-8") print repr(u2) # u'\u4e2d\u6587' s2 = u.encode("utf-8").decode("utf-8") # OK u2 = s.decode("utf8").encode("utf-8") # OK
另外一种方法就是更改python的默认编码为文件编码格式,例如以下所看到的(这里仅仅所以要reload sys模块。是由于python初始化后删除了setdefaultencoding方法):
#coding:utf-8 import sys reload(sys) sys.setdefaultencoding("utf-8") #更改默认编码为utf-8 u = u"中文" print repr(u) # u'\u4e2d\u6587' s = "中文" print repr(s) # '\xe4\xb8\xad\xe6\x96\x87' u2 = s.decode("utf-8") print repr(u2) # u'\u4e2d\u6587' s2 = u.decode("utf-8") u2 = s.encode("utf-8")
採用python的open()方法打开文件时,read()读取的是str,编码就是文件本身的编码。而调用write()写文件时,假设參数是unicode,则须要用指定编码encode,假设write()參数是unicode并且没有指定编码,则会採用python默认编码encode后再写入。
#coding:utf-8 f = open("testfile") s = f.read() f.close() print type(s) # <type 'str'> u = s.decode("utf-8") #testfile是utf-8编码 f = open("testfile", "w") f.write(u.encode("gbk")) #以gbk编码写入,testfile为gbk编码 f.close()
此外,python的codecs模块提供了一个open()方法。能够指定编码打开文件。使用这种方法打开文件读取返回是unicode。
写入时,假设write參数是unicode,则使用打开文件时的编码写入,假设是str,则先使用默认编码解码成unicode后再以打开文件的编码写入(这里须要注意假设str是中文,而默认编码sys.getdefaultencoding()是ascii的话会报解码错误)。
#coding:gbk import codecs f = codecs.open('testfile', encoding='utf-8') u = f.read() f.close() print type(u) # <type 'unicode'> f = codecs.open('testfile', 'a', encoding='utf-8') f.write(u) #写入unicode # 写入gbk编码的str,自己主动进行解码编码操作 s = '汉' print repr(s) # '\xba\xba' # 这里会先将GBK编码的str解码为unicode再编码为UTF-8写入 #f.write(s) #默认编码为ascii时。这会报解码错误。 f.close()
版权声明:本文博客原创文章,博客,未经同意,不得转载。
标签:
原文地址:http://www.cnblogs.com/mengfanrong/p/4637458.html