编码基础
这是ascii编码表, 从0到127, 每一个数字(code point)对应一个字符, 编码表就是这种对应
关系的映射表, 由于计算机只能处理字节, 所以还需要将数字保存为字节, ASCII编码
规定使用一个字节
一个字节提供的编码位是从0到255, 足以存下ascii编码表中所有字符, 为了支持更多语言, 人
们使用更多的字节来定义一个字符, 例如使用两个字节的gb2312
, big5
, 他们分别用来处
理中文简体和中文繁体
不同的语言使用不同的编码表导致大量不同的编码表出现, 于是人们就想能不能一套编码表包含
所有语言, 于是unicode
就出现了, unicode
总共有1100000个编码位(code point), 目前
用到了110000个, 每种语言中的每一个字符在unicode
中都使用一个编码位, 有了编码位与字
符之间的映射关系后, 还需要将编码位转成字节提供给计算机处理, ASCII
编码就是简单的使
用一个字节来保存编码位, unicode
标准定义了多种编码方式(encoding)来将编码位转成字
节, 例如UTF-8
, UTF-16
, UTF-32
, UCS-2
, UCS-4
等等, UTF-8
是我们常用的编
码, 它使用变长字节数来表示一个unicode
编码位, ASCII
中的字符在UTF-8
中也是使用一
个字节, 且相同, 所以ASCII
是UTF-8
的子集
python2中的编码
python2中有两种字符串类型, 一种是str
类型, 它储存的是字节, 另一种是unicode
, 它储
存的是编码位, 如下:
1 | s1 = 'hi 你好' |
str
类型的字符串保存的是字节, 所以使用len
函数计算长度返回的将是字节数, 而unicode
类型的字符串保存的是编码位, 将返回编码位个数
1 | print(len(s1))# 9 |
str
和unicode
的字符串可以互相转换, unicode
字符串可以通过encode
方法转变成储存
字节的str
类型, str
字符串可以通过decode
转变成unicode
1 | print(s1.decode('utf-8'))# hi 你好 |
s1
是str
类型, 保存的是计算机使用的字节码(Bytes), 它使用decode
方法根据UTF-8
编码表可以解码成unicode
, s2
是unicode
类型, 它可以使用encode
方法, 同样根据UTF-8
编码表可以转变成字节码(Bytes), 如果使用错误的编码类型, 将返回编码错误
1 | print(s1.decode('ascii')) |
python2中很多地方都会存在隐性转换, 比如尝试将unicode
字符串和str
类型(字节)拼接起
来, python2先会自动将str
字节字符串decode成默认编码类型的字符串, 然后再拼接
1 | print(u'hi' + ' nihao')# hi nihao |
python2中隐性的字符串类型转换在所有字符都是ascii时表现正常, 当存在其他编码字符时就
可能导致错误
python3中的编码
python3中也有两种类型的字符串, 直接由引号括起来的字符串是str
类型, 普通字符串加b
前缀的字符串属于bytes
类型
1 | s1 = 'hi 你好' |
python2中的str
等价于 python3中的bytes
python2中的unicode
等价于 python3中的str
python3中不会做任何隐性的类型转换, 如果拼接str
和bytes
类型的字符串, 将会抛出TypeError
错误
编码问题最佳实现
编码问题并不复杂, 只要遵循以下几点就可以避免大部分的编码问题, python2/3同样适用
1.bytes on the outside, Unicode on the inside.
进出你的程序的数据必须是bytes
类型, 在程序内部处理unicode
字符串
2.know what you have
必须知道自己处理的数据是什么类型的字符串, 要确定到底是bytes
还是unicdoe
类型,
如果是bytes
类型, 还需要知道它的编码是什么, 才可以根据对应的编码将bytes
转换
为unicode
, 但是, 数据的编码是无法仅仅根据bytes
类型的字符串本身得出来, 要么
从数据源处得知, 要么只能靠猜
总结
1.编码表保存编码位与字符之间映射关系,
unicode
支持所有的语言字符, 它兼容ascii
2.编码位(code points)是数字, 需要转换成字节才能让计算机处理, 转换规则由编
码方式决定, 例如ASCII
编码使用一个字节保存它所支持的127个字符,UTF-8
使
用可变长字节数保存unicode
字符, 其中,ASCII
中的字符在UTF-8
中是完全一
样的, 所以ASCII
是UTF-8
的子集3.python2有两种类型的字符串,
str
和unicode
,str
保存的是bytes
,unicode
保存的是unicode
,str
通过decode
方法可以转换成unicode
,unicdoe
通过encode
方法可以转换成bytes
,4.python3同样有两种类型的字符串,
str
和bytes
,str
保存的是unicode
,bytes
保存的是bytes
,str
通过encode
方法转换成bytes
bytes
通过decode
方法转换成str
5.python2中存在隐性转换字符串类型的现象, 例如拼接不同类型的字符串, 则会根据
默认编码自动将bytes
转换成unicode
再拼接, python3中拼接不同类型字符串则会
报错, tip1: 不要依赖自动转换, 任何时候都需要清楚的知道自己处理的字符串类型6.程序内部处理的字符串都应该是
unicode
类型, 出去的都应该是bytes
类型