热点新闻:Python编码问题详解

admin 1个月前 (05-28) 科技 8 1

1. 基本概念

  • 字符集(Character set)

    • 注释:文字和相符的总称
    • 常见字符集:
      • Unicode字符集
      • ASCII字符集(Unicode子集)
      • GB2312字符集
  • 编码方式(Encoding)

    • 注释:将字符对应到字节的方式,部门字符集和编码方式名称一样。
    • 常见编码方式:
      • UTF-8:可对Unicode字符举行编码
      • GB2312
      • ASCII
  • 编码(Encode)

    • 注释:将字符集中字符根据一定规则转换成字节
  • 解码(Decode)

    • 注释:与编码相反,将字节转换为字符集中的字符
  • 字符集与编码方式的关系

    • 每个字符集都有对应的编码方式
    • 一种字符集可能有多种编码方式
      • 差别的编码方式获得的字节差别,占用存储空间也纷歧样
      • 例如Unicode字符可以使用UTF-8/ASCII/GBK等方式编码
    • Unicode字符集包罗世界上大部门字符,许多其他字符集有的字符它都有,是他们的超集
    • 大部门字符集可以理解为Unicode的子集
    • 实际上,除了Unicode之外所谓的字符集主要是对Unicode部门字符编码而已(界说编码方式)
    • 一种编码不必支持Unicode的所有字符(通常把它能支持的那部门称为它的字符集)

2. 关于编码的错误和解决方式

在开发过程中,我们所接触的字符集大多都是Unicode,大部门报错都是关于编码和解码的。

2.1. 编码错误UnicodeEncodeError

2.1.1. 错误剖析

导致该错误的缘故原由通常是编码方式支持的Unicode字符不全;在工作中,你写了一个txt中文文档,想用ascii编码去保留这个文件,就会报这种错误。

错误复现:

我们知道ascii不支持字符,那我们用ascii编码方式对Unicode举行编码:

# -*- encoding: utf-8 -*- 
u"中".encode(encoding='ascii')

报错如下:

UnicodeEncodeError: 'ascii' codec can't encode character '\u4e2d' in position 0: ordinal not in range(128)

这是一个UnicodeEncodeError 类型的错误,提醒无法使用指定的编码方式对字符举行编码,报错提醒中可以获得3个信息:

  • 当前使用的是acsii编码方式
  • 被编码的字符是'\u4e2d'
  • ascii编码方式能支持的字符有128个

有时刻我们还可以行使这个提醒查看编码方式支持的字符个数:

# -*- encoding: utf-8 -*- 
u"中".encode(encoding='iso-8859-1')

报错:

UnicodeEncodeError: 'latin-1' codec can't encode character '\u4e2d' in position 0: ordinal not in range(256)

通过报错提醒可以看出iso-8859-1能编256个字符。

接着,我们来看下用支持中文的utf-8 编码方式举行编码能获得什么效果:

# -*- encoding: utf-8 -*-
s = u"中".encode(encoding='utf-8')
print("s: ", s)
print("s == 中?" , s == '中')
print("type of s: ", type(s))
print("str==bytes? ", bytes == type(s))

输出:

('s: ', '\xe4\xb8\xad')
('s == \xe4\xb8\xad?', True)
('type of s: ', <type 'str'>)
('str==bytes? ', True)

从输出的效果可以获得:

  • 编码获得的工具跟我们直接界说的字符串是一样的,都是str
  • str就是bytes(python中)

2.1.2. 解决方式

UnicodeEncodeError 是说编码方式支持的字符不全,而UTF-8编码就能很好地对Unicode编码,以是只要把编码方式指定为utf-8就可以了。

在python2中:

若是你挪用encode方式但没有指定encoding参数,那很可能使用了系统默认的参数,就像:

# -*- encoding: utf-8 -*-
import sys
print "default encoding is %s ." % sys.getdefaultencoding()
u'中'.encode()

输出:

default encoding is ascii .
UnicodeEncodeError: 'ascii' codec can't encode character u'\u4e2d' in position 0: ordinal not in range(128)

可以手动指定encoding参数,也可以修改python默认编码方式:

# -*- encoding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')  # 必须在reload之后挪用

print u'中'.encode()

在python3中:

在python3中你很难看到UnicodeEncodeError了,由于python3的默认编码就是utf-8,而Unicode字符都可以用utf-8编码方式编码。

2.2. 编码错误UnicodeDecodeError

2.2.1. 错误剖析

导致该错误的缘故原由是使用了错误的解码方式把字节数据还原成字符。例如在工作中,有一个utf-8天生中文文档,我们选择用ascii编码解码,就会报这个错。

错误复现:

我们知道python中字符串和字节是一样,我们可以界说一个中文字符串,通过ascii来解码天生Unicode,复现这个错误:

# -*- encoding: utf-8 -*-
print '中'.decode(encoding='ascii')

输出:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

注重,这是一个UnicodeDecodeError错误,区别于编码错误UnicodeEncodeError,它提醒无法把字节0xe4(实际上对应三字节,0xe4是第一个) 解码成Unicode。0xe4转换为10进制是228,已经跨越127了,以是ascii无能力了。

2.2.2. 解决方式

我们需要知道天生字节的编码方式才气举行还原,就好像对一个文件举行了加密,必须得知道加密的密码才气把文件还原,而解码方式(或者称为编码)就是谁人密码。 以是不管是python2照样python3直接去修改默认编码为UTF-8纷歧定能解决问题,详细的方式有两种:

  1. 通过源码找到解码失败的字节是使用那种编码天生的
  2. 对报错的字节数据使用种种常见的编码举行解码,考察哪一种是准确的

以一个例子来说明为什么直接设置默认编码为UTF-8不能有用解决UnicodeDecodeError问题

python文件头指定了编码为,在声明字符串时刻将会使用指定的编码转换为字节:

# -*- encoding: GBK -*-
s = "张"
print ("s is ", s)

s_unicode = u'张'
print ("encoding with GBK is ", s_unicode.encode("GBK"))
print ("encoding with UTF-8 is ", s_unicode.encode("UTF-8"))

输出:

('s is ', '\xd5\xc5')
('encoding with GBK is ', '\xd5\xc5')
('encoding with UTF-8 is ', '\xe5\xbc\xa0')

在文件头中指定了GBK编码后默认情况下字符就会被编码为\xd5\xc5,这与我们手动用GBK编码获得效果一致,而使用utf-8编码获得的是3个字节的数据\xe5\xbc\xa0(使用了更多的存储空间)。

例子最先了,在python2中将一个dict转换成json:

# -*- encoding: GBK -*-
import json
d = {'name': "张", 'sex': u'man'}
print (json.dumps(d))

输出:

UnicodeDecodeError: 'utf8' codec can't decode byte 0xd5 in position 0: invalid continuation byte

错误说无法使用utf-8解码0xd5,0xd5也就是GBK中的张,我们知道这个字节是用GBK天生的,这个时刻可以设置json.dumps的encoding参数解决:

# -*- encoding: GBK -*-
import json
d = {'name': "张", 'sex': u'man'}
print (json.dumps(d, encoding='gbk'))

修改一下代码,继续使用我们熟悉的utf-8编码来执行:

# -*- encoding: utf-8 -*-
import json
d = {'name': "张", 'sex': u'man'}
print (json.dumps(d, encoding='utf-8'))

输出:

{"name": "\u5f20", "sex": "man"}

发现name是unicode,使用eNSure_ascii=False,不强制转换成ascii:

# -*- encoding: utf-8 -*-
import json
d = {'name': "张", 'sex': u'man'}
print (json.dumps(d, encoding='utf-8', ensure_ascii=False))

输出:

  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 251, in dumps
    sort_keys=sort_keys, **kw).encode(obj)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 210, in encode
    return ''.join(chunks)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 1: ordinal not in range(128)

纳尼,文件头也是utf-8,也指定了utf-8怎么照样报错?错误提醒用ascii去解码0xe5字节,在上面的代码输出中可以知道0xe5是utf-8对字符编码的第一个字节 ,报错的缘故原由是用ascii去剖析utf-8天生的字节了。我们并没有设置哪个地方使用ascii解码,应该是系统默认的编码,实验设置系统默认编码再执行:

# -*- encoding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import json
d = {'name': "张", 'sex': u'man'}
print (json.dumps(d, encoding='utf-8', ensure_ascii=False))

输出:

{"name": "张", "sex": "man"}

3. 总结

3.1. python2和python3对字符串的处置区别

  • Python2
    • 默认编码是ascii
  • Python3
    • 默认编码为utf-8
    • 不能使用import sys;sys.setdefaultencoding('utf-8')设置默认编码
    • Unicode和str都用字符串示意了

3.2. 为什么不全用UTF-8编码?

UTF-8包罗的字符更多,占用的内存和磁盘空间也更大,比如对汉字,utf-8是3个字节,gbk是2个字节。

3.3. 若何快速解决UnicodeEncodeError错误?

python3中基本不会泛起,python2中实验设置默认编码为utf-8。

3.4. 快速解决UnicodeDecodeError?

需要知道失足的字节是使用哪种编码方式天生的,然后实验把默认编码设置成这种。

,

Sunbet

Sunbet www.817603.com Sunbet(www.sunbet.red)是进入Sunbet的官方站点。Sunbet开放Sunbet会员开户网址、Sunbet代理开户、Sunbet手机版下载、Sunbet电脑客户端下载等业务

AllBetGaming声明:该文看法仅代表作者自己,与本平台无关。转载请注明:热点新闻:Python编码问题详解

网友评论

  • (*)

最新评论

  • 新皇冠会员APP 2020-05-28 00:24:20 回复

    Sunbet秉承以客为先的理念,多年运营、专业团队、专注服务、值得信赖。姐妹们快看神仙

    1

站点信息

  • 文章总数:594
  • 页面总数:0
  • 分类总数:8
  • 标签总数:928
  • 评论总数:180
  • 浏览总数:4659