【转】【Python】python中的编码问题报错
asciicodeccantdecode。。。
1.unicode、gbk、gb2312、utf-8的关系
2.python中的中⽂编码问题
2.1 .py⽂件中的编码
  Python 默认脚本⽂件都是 ANSCII 编码的,当⽂件中有⾮ ANSCII 编码范围内的字符的时候就要使⽤"编码指⽰"来修正。⼀个module 的定义中,如果.py⽂件中包含中⽂字符(严格的说是含有⾮anscii字符),则需要在第⼀⾏或第⼆⾏指定编码声明:
2.2 python中的编码与解码
  先说⼀下python中的字符串类型,在python中有两种字符串类型,分别是str和unicode,他们都是basestring的派⽣类;str类型是⼀个包含Characters represent (at least) 8-bit bytes的序列;unicode的每个unit是⼀个unicode obj;所以:
len(u'中国')的值是2;len('ab')的值也是2;
  在str的⽂档中有这样的⼀句话:The string data type is also used to represent arrays of bytes, e.g., to hold data read from a file. 也就是说在读取⼀个⽂件的内容,或者从⽹络上读取到内容时,保持的对象为str类型;如果想把⼀个str转换成特定编码类型,需要把str转为Unicode,然后从unicode转为特定的编码类型如:utf-8、gb2312等;
python中提供的转换函数:
unicode转为 gb2312,utf-8等
# -*- coding=UTF-8 -*-
if __name__ == '__main__':
s = u'中国'
s_gb = s.encode('gb2312')
utf-8,GBK转换为unicode 使⽤函数unicode(s,encoding) 或者s.decode(encoding)
# -*- coding=UTF-8 -*-
if __name__ == '__main__':
s = u'中国'
#s为unicode先转为utf-8
s_utf8 =  s.encode('UTF-8')
assert(s_utf8.decode('utf-8') == s)
普通的str转为unicode
# -*- coding=UTF-8 -*-
if __name__ == '__main__':
s = '中国'
su = u'中国''
#s为unicode先转为utf-8
#因为s为所在的.py(# -*- coding=UTF-8 -*-)编码为utf-8
s_unicode =  s.decode('UTF-8')
assert(s_unicode == su)
#s转为gb2312,先转为unicode再转为gb2312
s.decode('utf-8').encode('gb2312')
#如果直接执⾏s.encode('gb2312')会发⽣什么?
# -*- coding=UTF-8 -*-
if __name__ == '__main__':
s = '中国'
#如果直接执⾏s.encode('gb2312')会发⽣什么?
这⾥会发⽣⼀个异常:
Python 会⾃动的先将 s 解码为 unicode ,然后再编码成 gb2312。因为解码是python⾃动进⾏的,我们没有指明解码⽅式,python 就会使⽤ sys.defaultencoding 指明的⽅式来解码。很多情况下 sys.defaultencoding 是 ANSCII,如果 s 不是这个类型就会出错。
拿上⾯的情况来说,我的 sys.defaultencoding 是 anscii,⽽ s 的编码⽅式和⽂件的编码⽅式⼀致,是 utf8 的,所以出错了: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
对于这种情况,我们有两种⽅法来改正错误:
⼀是明确的指⽰出 s 的编码⽅式
#! /usr/bin/env python
# -*- coding: utf-8 -*-
s = '中⽂'
s.decode('utf-8').encode('gb2312')
⼆是更改 sys.defaultencoding 为⽂件的编码⽅式
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys) # Python2.5 初始化后会删除 sys.setdefaultencoding 这个⽅法,我们需要重新载⼊
sys.setdefaultencoding('utf-8')
str = '中⽂'
⽂件编码与print函数
建⽴⼀个⽂件,⽂件格式⽤ANSI,内容为:
abc中⽂
⽤python来读取
# coding=gbk
print open("").read()
结果:abc中⽂
把⽂件格式改成UTF-8:
结果:abc涓 枃
显然,这⾥需要解码:
# coding=gbk
import codecs
print open("").read().decode("utf-8")
结果:abc中⽂
上⾯的我是⽤Editplus来编辑的,但当我⽤Windows⾃带的记事本编辑并存成UTF-8格式时,
运⾏时报错:
Traceback (most recent call last):
File "ChineseTest.py", line 3, in <module>
print open("").read().decode("utf-8")
UnicodeEncodeError: 'gbk' codec can't encode character u'/ufeff' in position 0: illegal multibyte sequence
原来,某些软件,如notepad,在保存⼀个以UTF-8编码的⽂件时,会在⽂件开始的地⽅插⼊三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。
因此我们在读取时需要⾃⼰去掉这些字符,python中的codecs module定义了这个常量:
# coding=gbk
import codecs
data = open("").read()
if data[:3] == codecs.BOM_UTF8:
data = data[3:]
print data.decode("utf-8")
结果:abc中⽂
(四)⼀点遗留问题
在第⼆部分中,我们⽤unicode函数和decode⽅法把str转换成unicode。为什么这两个函数的参数⽤"gbk"呢?
第⼀反应是我们的编码声明⾥⽤了gbk(# coding=gbk),但真是这样?
修改⼀下源⽂件:
# coding=utf-8
s = "中⽂"
print unicode(s, "utf-8")
运⾏,报错:
Traceback (most recent call last):
File "ChineseTest.py", line 3, in <module>
s = unicode(s, "utf-8")
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-1: invalid data
显然,如果前⾯正常是因为两边都使⽤了gbk,那么这⾥我保持了两边utf-8⼀致,也应该正常,不⾄于报错。
更进⼀步的例⼦,如果我们这⾥转换仍然⽤gbk:
# coding=utf-8
s = "中⽂"
print unicode(s, "gbk")
结果:中⽂
python中的print原理:
  When Python executes a print statement, it simply passes the output to the operating system (using fwrite() or something like it), and some other program is responsible for actually displaying that output on the screen. For example, on Windows, it might be the Windows console subsystem that displays the result. Or if you're using Windows and running Python on a Unix box somewhere else, your Windows SSH client is actually responsible for displaying the data. If you are running Python in an xterm on Unix, then xterm and your X server handle the display.
  To print data reliably, you must know the encoding that this display program expects.
简单地说,python中的print直接把字符串传递给操作系统,所以你需要把str解码成与操作系统⼀致的格式。Windows使⽤CP936(⼏乎与gbk 相同),所以这⾥可以使⽤gbk。
最后测试:
# coding=utf-8
s = "中⽂"
print unicode(s, "cp936")url编码和utf8区别
# 结果:中⽂
这也可以解释为何如下输出不⼀致:
>>> s="哈哈"
>>> s
'\xe5\x93\x88\xe5\x93\x88'
>>> print s  #这⾥为啥就可以呢? 见上⽂对print的解释
哈哈
>>> import sys
>>> defaultencoding()
'ascii'
>>> de('utf8')  # s在encode之前系统默认按ascii模式把s解码为unicode,然后再encode为utf8
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
>>> print s.decode('utf-8').encode('utf8')
哈哈
>>>
编码问题测试
使⽤ chardet 可以很⽅便的实现字符串/⽂件的编码检测
例⼦如下:
>>>
import
urllib
>>>
rawdata = urllib
.urlopen
(
'le/'
)
.read
(
)
>>>
import
chardet
>>>
chardet.detect
(
rawdata)
{
'confidence'
: 0.98999999999999999
, 'encoding'
: 'GB2312'
}
特别提⽰:
参考⽂献
JS从URL上获取中⽂字符,默认获取到是⼆进制码:
encodeURI ⽅法返回⼀个编码的 URI。
decodeURI,返回初始的字符串即正常显⽰中⽂字符。
encodeURI ⽅法不会对下列字符进⾏编码:":"、"/"、";" 和 "?"。请使⽤ encodeURIComponent ⽅法对这些字符进⾏编码。使⽤⽅法:decodeURI(url),encodeURI (url)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。