令人头疼的Python编码问题

89 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

前言

你是否在编写Python代码时,老是遇到UnicodeDecodeError/UnicodeEncodeError错误,无从下手。或者是打印一串字符串,确是乱码,搞人心态。

别慌,本文将从编码的前世今生讲解,让你对编码有个深刻了解,以便后期对Python编码问题进行分析和解决。

字符编码的前世今生

大家都知道,电脑本身是不认识字符的,只认识0和1。所以说,电脑的字符需要通过转换为0和1才能被电脑所识别,其实,让字符转换为被电脑识别的01数字的过程,就是字符编码。

当然,字符编码需要定义一套标准,不然电脑就没法准确识别字符了。标准这东西大家都懂的,大部分都是国外先定标准,国内再定,而且很难做到统一。

基于英文的ASCII码,由一个字节表示,一个字节就是8bit,顾名思义就是最大能代表256个字符(2的8次方)。256个字符对付英文绰绰有余,但是中国文字这么多,显然 ASCII码就不适用了。中国人定制了GBK,但是每个国家都自己定制,那就很难统一。

这时候万国码Unicode编码出现,采用了两个字节进行编码,那现在问题也来,就是英文字母一个字节就能搞定,现在都要两个字节,那不是很浪费内存吗。可变长度编码UTF-8出现,解决了这个问题,字母就用一个字节,复杂的字符就用两个字节。

总结下,Unicode编码占用空间,但运行速度快,UTF-8恰恰相反,所以内存中用Unicode编码,而存储用UTF-8,这个大家要好好记着。

Python3编码

首先,Python3默认编码为utf-8。

import sys
print(sys.getdefaultencoding())

# utf-8

然后,Python分为str和bytes两种数据类型,文本字符为str,str能表示Unicode 字符集中所有字符,bytes代表二进制数据。

a = 'a'
b = '罗攀'
print(type(a),type(b))

c = b'\xe7\xbd\x97\xe6\x94\x80'
print(c,type(c))

#<class 'str'> <class 'str'>
#b'\xe7\xbd\x97\xe6\x94\x80' <class 'bytes'>

encode 与 decode

之前的错误分为UnicodeDecodeError和UnicodeEncodeError,其实就是编码和解码错误。

简单的说,从字符转为电脑能识别的01,就是编码,01转换为字符,就是解码。这里的编码和解码必须一致,不然就会报错。

str 与 bytes 之间的转换就是用 encode 和从decode 方法。

a = '罗攀'
print(a.encode('utf-8'))
print(a.encode('utf-8').decode('utf-8'))
print(a.encode('gb2312').decode('utf-8'))

# b'\xe7\xbd\x97\xe6\x94\x80'
#罗攀
#Traceback (most recent call last):
#  File "/Users/luopan/Python练习/编码问题.py", line 25, in #<module>
#    print(a.encode('gb2312').decode('utf-8'))
#UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc2 in position 0: invalid continuation byte

案例分析

例如,我在本地新建一个txt,编码为utf-16。

image.png

如果我们直接读取文件,就会报错,那是因为python默认编码为utf-8。

image.png 所以我们需要指定编码即可。

image.png

我们下期再见~