字符编码
是否重要取决于编程场景,对只处理 ASCII 文本的程序员没有影响
字符编码
Python3 明确区分了人类可读的 文本字符串 和原始的 字节序列
1. 字符
1.1 编码中的字符串
字符串: 字符组成的序列,问题出现在 “字符” 的定义上
注
字符: 2015 年将字符最佳定义为 Unicode 字符,因此 Python3 的 str
对象获取的元素就是 Unicode 字符
Unicode 标准把 字符的标识 和具体的 字节表述 进行了如下区分
- 字符的标识:即
码位
,是0 ~ 1 114 111
的数字 (十进制),在 Unicode 标准中以4 ~ 6
个十六进制数字表示,而且加前缀U+
A
的码位 为U+0041
- 字节表述:取决于所用的编码,在 UTF-8 编码中,
A (U+0041)
的码位编码为单字节\x41
,而在UTF-16LE
编码中编码成两个字节\x41\x00
- 编码:在
码位
和字节序列
之间转换时使用的算法
提示
把 码位
(字符串) 转换成 字节序列
(字节串) 的过程是编码(encode),把 字节序列
转化为 码位
的过程是解码(decode)
s = "coffeé"
print(len(s))
b_sequence = s.encode("utf8")
print(b_sequence, len(b_sequence))
print(b_sequence.decode("utf8"))
### 输出结果
# 6
# b'coffe\xc3\xa9' 7
# coffeé
- 字符串
coffeé
有 6 个 Unicode 字节 s.encode("utf8")
使用UTF-8
把str
对象 编码为bytes
对象,该对象以b
开头- 字节序列
b_sequence
有 7 个字节(在UTF-8
中é
的码位编码成 2 个字节) - 使用
bytes.decode("utf-8")
将bytes
对象解码为str
对象
1.2 Python 编码发展史
1.2.1 ASCII 码
用 8 位,即 一个字节 表示字符 0 ~ 127
已编好的 英文 和 拉丁字符
提示
后为了扩容,各国根据索引等方式又进行进一步的编码
中国:
gb2312
: 只收录了约 6700 多个中文 (1980 年)gbk1.0
: 收录了 2 万 多个字符 (1995 年)gb18030
:27000 左右中文 (2000 年)
1.2.2 Unicode 万国码
Unicode: 兼容各国的编码,是一种国际通用标准, utf-8
则是 Unicode 的子集
utf-32
: 即一个字符占 32 位 4 字节utf-16
: 一个字符占 2 字节 及以上,65535utf-8
: Unicode 的子集,英文用 ASCII 码 来存储亚洲国家,如: 中 / 日 用 3 个字节
1.2.3 Python 的编码
Python2 的默认编码为 ASCII 码,字符串也都是字节,故文件头通常声明编码方式,如
#-- coding:utf-8 --
- Python2 要声明
coding:utf-8
,告诉用 ASCII 编码解释器是 utf-8 编码的文件- 解释器: 打开文件,将一行行代码放到内存解释
- 而 Python2 存储的也是 utf-8 编码的文件
- 解释器 和 磁盘存盘的编码一致 才能顺利执行,不会乱码
Python3 则不同于 2,默认是 Unicode 万国码,u''
(省略)表示,故可以在 gbk
编码下正常显示中文
import sys
# 检测系统编码
sys.getdefaultencoding()
## 'utf-8'
str_a = u"中文字符串"
str_a.encode("utf-8")
## b'\xe4\xb8\xad\xe6\x96\x87\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2'
bytes_b = str_a.encode("gbk")
## b'\xd6\xd0\xce\xc4\xd7\xd6\xb7\xfb\xb4\xae'
bytes_b.decode("gbk")
## '中文字符串'
str_a
定义了一串中文字符串,不同编码形式的下的字节串不同b''
即 bytes 字节,为 16 进制[0-255]
的数字,每个国家都有自己的 bytesstr_a.encode("gbk")
返回了按 gbk 编码后, bytes 类型的字节串码(密文)bytes_b.decode("gbk")
按照 gbk 编码,又解码回为原来的 Unicode 字符串
编码、转码通常在 数据传输、交互 等使用
若需要查看中文字符的万国码,可使用
s = "你好hello"
json.dumps(s)
## '"\\u4f60\\u597dhello"'
Python3 下 .py
存储的文件,的确是 utf-8 编码,但内存生成时会变为 Unicode 编码,这是为了符合 ISO 统一标准,传给 解释器 执行
2. 常见问题
2.1 操作系统编码
查看 Linux 操作系统语言环境变量
$ echo $LANG
# zh_CN.UTF-8 或 en_US.UTF-8 之类的
当出现中文时,可能会导致引用的库,执行命令异常,如 nmcli
# 源码: nmcli._syscmd = SystemCommand().nmcli
# 默认 'LAN' 为 C
r = self._run(commands, capture_output=True, check=True, env={'LANG': 'zh_CN.UTF-8'})
此时需对源码进行继承和改写
或若允许,可直接设置环境变量为
C.UTF-8
$ export LANG=C.UTF-8