Python编码问题详解

简介:

Python编码问题详解

  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的所有字符(通常把它能支持的那部分称为它的字符集)

  1. 关于编码的错误和解决方法
    在开发过程中,我们所接触的字符集大多都是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: ', 'xe4xb8xad')
('s == xe4xb8xad?', True)
('type of s: ', )
('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不一定能解决问题,具体的方法有两种:

通过源码找到解码失败的字节是使用那种编码生成的
对报错的字节数据使用各种常见的编码进行解码,观察哪一种是正确的
以一个例子来说明为什么直接设置默认编码为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 ', 'xd5xc5')
('encoding with GBK is ', 'xd5xc5')
('encoding with UTF-8 is ', 'xe5xbcxa0')
在文件头中指定了GBK编码后默认情况下字符张就会被编码为xd5xc5,这与我们手动用GBK编码得到结果一致,而使用utf-8编码得到的是3个字节的数据xe5xbcxa0(使用了更多的存储空间)。

例子开始了,在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"}

  1. 总结
    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?
需要知道出错的字节是使用哪种编码方式生成的,然后尝试把默认编码设置成这种。

原文地址https://www.cnblogs.com/oaks/p/12776124.html

相关文章
|
6月前
|
存储 Python
Python文件编码概念详解
Python文件编码概念详解
61 1
|
2月前
|
Python
python第三方库-字符串编码工具 chardet 的使用(python3经典编程案例)
这篇文章介绍了如何使用Python的第三方库chardet来检测字符串的编码类型,包括ASCII、GBK、UTF-8和日文编码的检测示例。
137 6
|
2月前
|
Python
Python 中如何指定 open 编码为ANSI
Python 中如何指定 open 编码为ANSI
|
3月前
|
数据采集 开发工具 Python
海康威视工业相机SDK+Python+PyQt开发数据采集系统(支持软件触发、编码器触发)
该系统基于海康威视工业相机SDK,使用Python与PyQt开发,支持Gige与USB相机设备的搜索及双相机同时显示。系统提供软件触发与编码器触发模式,并可在数据采集过程中实时保存图像。此外,用户可以调节曝光时间和增益,并进行信息输入,这些信息将被保存至配置文件以便下次自动加载。参数调节与实时预览等功能进一步增强了系统的实用性。
208 1
|
3月前
|
开发者 Python
Python编码风格
Python编码风格
27 1
|
3月前
|
JSON 数据库 开发者
FastAPI入门指南:Python开发者必看——从零基础到精通,掌握FastAPI的全栈式Web开发流程,解锁高效编码的秘密!
【8月更文挑战第31天】在当今的Web开发领域,FastAPI迅速成为开发者的热门选择。本指南带领Python开发者快速入门FastAPI,涵盖环境搭建、基础代码、路径参数、请求体处理、数据库操作及异常处理等内容,帮助你轻松掌握这一高效Web框架。通过实践操作,你将学会构建高性能的Web应用,并为后续复杂项目打下坚实基础。
118 0
|
4月前
|
Python
11个提升Python列表编码效率的高级技巧
Python中关于列表的一些很酷的技巧
54 1
|
4月前
|
存储 缓存 Python
python中小数据池和编码
python中小数据池和编码
56 3
|
4月前
|
缓存 Java Unix
python中内存管理等10个编码习惯
【7月更文挑战第3天】本文涵盖了Python编程中的变量管理、模块导入、命令行参数、内存管理和面向对象设计的10个关键概念。
47 0
python中内存管理等10个编码习惯
|
5月前
|
自然语言处理 Python
Python编码问题
Python编码问题是指在处理文本时,由于编码不一致导致程序不能正确处理文本的问题。在Python中,编码问题主要有两种情况:文件编码问题和字符串编码问题。
67 7
下一篇
无影云桌面