恼人的 Python 编码

正文索引 [隐藏]

一、编码常识

ASCII:英文编码,存储长度 1 byte

Unicode:万国语言编码,未定义存储长度

ASCII 存储方便,表达力不行(只能表示英文),Unicode 表达能力强,存储浪费空间极大

UTF-8:Unicode 实现方法之一,存储长度 1~4 bytes

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。对于英语字母,UTF-8 编码和 ASCII 码是相同的
  • 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码

GBK:中文编码,存储长度 2 bytes

参考:阮一峰:字符编码笔记

二、string 的 encode、decode 逻辑

字符串在 python 的 str 里使用 Unicode 编码,编码转换时,通常需要用 unicode 作为中间编码,逻辑如下
1565789167217

如果需要传输这些字符,则需要进行字符编码,这时候需要将 str 进行编码,

三、python2,python3 对字符串处理的差异

1. 默认编码

首先解释一下默认编码,这个是 python 脚本默认使用的编码,主要影响的有:文件的读取、输入输出流的读取等,文件的读取在使用 open 的时候可以强制指定编码、解码格式,但是默认编码使用 ascii,输入输出一旦含有中文立刻锟斤拷。

python2 默认编码 ascii,python3 默认编码 utf-8,调用 sys.getdefaultencoding() 查看

1565786360072

1565786371877

这也是为什么 python2 中如果要写中文,需要指定默认编码的原因:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

不写这个会出现的结果就是。。。

2. 编码解码问题

这个问题非常恶心,首先要知道,Unicode 就是用来解码的,其他编码是用来编码的,把上面那张图办下来帮助理解:

1565789167217

python2

str 指 bytes(就是已经经过编码,而且是用默认的 ascii 编码),这个玩意儿还能 encode。。。没卵用,用了就报错。。。同样 unicode 有一个 decode,一用就报错,卵用没有,但是喜滋滋将 str 进行 decode 的时候,会出现下面结果

1565795677636

啊啊啊啊啊,这是为啥,原因 python2 会对于 Unicode 对象自动执行 ascii 编码转化为 str,执行 a.encode('utf-8') 相当于执行了 a.encode('ascii').decode('ascii'),ascii 不支持中文,所以就会报错,因此使用 python2 时,大多中文字符串加上 u 前缀,统一编码为 utf-8

python3

str 就是指 unicode,如果想得到 bytes,就需要字符串加前缀 b(但字符串不能含中文),或者进行 encode,这样使用起来就非常清晰方便

1565797871432

总结

编码问题非常讨厌,报错报到头秃。。。在需要网络传输字符数据的时候尤为重要,如果使用爬虫啊,解析 http 包啊这类东西,搞不清楚编码能把人磕碜死(流下没技术的泪水)