一文搞懂Python字符编码(编码方式、乱码和报错原因)

1.字符编码的出现

  • 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。

  • 因此,字符编码就是制定一个编码表将字符和编码(可以简单理解为数字)对应起来。字符编码将每一个字符和一个编码唯一对应起来。这样我们就能在计算机上保存字符对应的编码,而在我们查看它时,通过编码表就可以把它对应的字符显示出来。

2.不同的编码方式

上述处理方式是不是看起来很完美?但不幸的是,世界上有上千种语言,要把所有语言的字符都加进来是非常困难的。所以很多国家都有自己的编码,例如 gbk就是我国所使用的的国标编码方式,日本把日文编码到Shift_JIS 里、韩国把韩文编码到Euc-kr 里。各个国家可能都有自己的编码标准,使用不同的编码方式,就可能会出现乱码的情况。下面是几种最常见的编码:

  1. ASCII编码

最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码

  1. GB2312和GBK编码

中国制定了GB2312编码,用来把中文编进去,而后有颁布了GBK编码。GB2312是简体汉字编码规范,但GBK是大字符集,不仅包含了简体中文,繁体中文还包括了日语、韩语等所有亚洲文字的双字节字符。

  1. Unicode字符集

为了解决不同编码造成的乱码问题,Unicode字符集应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode又被称为统一码、万国码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

  1. UTF-8

如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。

3.乱码原因解读

对于不同的编码方式,有一点值得我们注意:

  • GB2312、GBK以及UTF-8这几种编码都是兼容ASCII码。这也就是说,当我们对英文字符和数字编码时,不论我们使用哪一种编码方式,都可以正确解读出来。

这也就说明了,对于一个纯英文和数字的文本文件,无论我们使用的是哪一种编码,都不会出现乱码的情况。

  • 因此,我们常常遇到的乱码问题,绝大部分都是因为GBK和UTF-8对于中文的编码方式不同。

当我们使用GBK编码保存了一个包含中文的文本文件,再通过UTF-8对这个文件解码时,就会出现乱码。

同样,当我们使用UTF-8编码保存了一个包含中文的文本文件,再通过GBK对这个文件解码时,就会出现乱码。

通过简单的Python代码就可以清晰的看出原因:

print('ABC'.encode('ascii'))    # 对'ABC'用ascii编码
print('ABC'.encode('gbk'))
print('ABC'.encode('utf-8'))

# print('你好'.encode('ascii')) 报错,ascii不能编码中文
print('你好'.encode('gbk'))
print('你好'.encode('utf-8'))

输出如图所示:

这个简单的代码,清晰的展示出了:英文字符使用ASCII编码、GBK编码和UTF-8编码的方式相同,不会出现解读错误的情况,也就不会出现乱码。而对于中文字符,gbk中一个汉字编码为两个字节,而utf-8中一个汉字编码为三个字节,两者的编码方式不同。因此,当用GBK解读UTF-8编码的文本或用UTF-8解读GBK编码的文本时,会出现乱码或报错。

4.补充(乱码 or 报错?)

你可能会发现,但你在Python中用一种编码解读另一种编码的文本时,有时会出现乱码,但有时会直接报错。这是为什么呢?

不知道大家在看上面代码的时候,有没有想到一个问题。gbk中一个汉字编码为两个字节,而utf-8中一个汉字编码为三个字节,那么对于一个汉字,你用错编码方式,是一定会报错的。

print('你'.encode('gbk').decode('utf-8'))    # 对'你'用gbk编码,再用utf-8解码
print('你'.encode('utf-8').decode('gbk'))

这两条语句都会报错,报错信息就是大家时常会遇到的解码错误:

第一句:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte

第二句:

UnicodeDecodeError: 'gbk' codec can't decode byte 0xa0 in position 2: incomplete multibyte sequence

一个汉字会报错,那如果我有两个汉字呢?

print('你好'.encode('utf-8').decode('gbk'))    # 对'你好'用gbk编码,再用utf-8解码
print('你好'.encode('gbk').decode('utf-8'))

结果如下:

第一条语句解码为了三个汉字,与初始不同,第二条语句报错。看到这里不知道你发现了原因没有?

utf-8中一个汉字编码为三个字节,那么两个汉字就被编码为6个字节,而gbk中一个汉字编码为两个字节,因此使用gbk解码时,这6个字节可以被划分为3的部分,对应3个汉字。

而在第二条语句中,gbk将两个汉字编码为了4个字节,而utf-8是解码不了4个字节的。这也就解释了报错信息后面的:incomplete multibyte sequence(不完整的多字节序列)。

由此,可以得出结论,对于一句中文,当使用gbk编码时,如果编码的字节总数为3的整数倍,就能够用utf-8解码出来,只不过内容不一样。而当使用utf-8编码时,如果编码的字节总数为2的整数倍,就能够用gbk解码出来,只不过内容不一样。

猜你喜欢

转载自blog.csdn.net/lyb06/article/details/129676450
今日推荐