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

Python编码问题

2015-07-10 20:41 901 查看

Python编码问题总结


下面的文章和编码具体解释总结了常见字符编码后,这篇文章会对python中常见的编码问题进行分析和总结。因为python3.x版本号和python2.x版本号在字符编码方面有非常大差异,所以本文都是以Python2.7.5来分析2.x版本号中的字符编码问题。


1.Python编码基础

1.1 str和unicode

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类型[code]“中文”
实际是
"\xe4\xb8\xad\xe6\x96\x87"


而对于unicode类型u“中文”(实际是
u"\u4e2d\u6587"
),使用len()函数得到结果是2.[/code]

1.2 头部编码声明

在python源码文件里假设实用到非ascii字符,比方中文,那么须要在源码文件头部声明源码字符编码,格式例如以下:

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


这个格式看起比較复杂,事实上python仅仅检查#、coding,编码等字符串,能够简写成#coding:utf-8,甚至还能够写成#coding:u8。


2.Python2.x常见编码问题

2.1 头部编码声明和文件编码问题

文件头部编码声明决定了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
错误。

2.2 默认编码问题

以下看个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方法。由于假设是直接调用。则相当于[code]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...
错误。[/code]
上面样例中凝视掉的两行代码假设运行就会报错,当然,假设本身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")

2.3读写文件编码

採用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()



3.參考资料

python字符编码详细解释
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: