理解Python的编码问题

一、字符编码初探
字符编码其实就是将人类能识别的字符与计算机能识别的数字对应起来 。ASCII(American Standard Code for Information Interchange)美国信息交换标准代码,是最早最通用的单字节编码标准 。
ASCII单字节编码表示范围有限,是不能满足表示中文的,于是基于ASCII扩展,制定了GB2312标准(GB是国标的意思) 。现在最常用的中文编码标准GBK又是GB2312的升级,能表示更多的字符 。
计算机的发展和普及在各个国家和地区各有不同,各国也是制定了自己的编码标准,这些基于ASCII扩展而来,使用多字节表示字符的延伸编码方式称为 ANSI 编码 。在简体中文windows系统中,ANSI编码代表GBK,而韩文系统中ANSI编码代表EUC-KR 。
由于不同国家和地区编码标准不一致,也导致了它们之间存在复杂的编码转换,于是诞生了unicode编码方式,以提供统一的编码标准,所以unicode也叫万国码,其标准称呼应该是Universal Multiple-Octet Coded Character Set,简称UCS 。而unicode又存在多种编码方式的实现,其中UTF-8是最常用的一种UTF(UCS Transfer Format)标准 。
二、Python2/python3的默认编码python2的默认编码是ascii,python3则是utf-8 。可以通过如下方式获取:
python2 -c "import sys;print(sys.getdefaultencoding())"python3 -c "import sys;print(sys.getdefaultencoding())"可以在python文件开头设置默认编码,python3默认就使用了utf-8,所以不需要该编码声明 。
# -*- coding: UTF-8 -*-# coding=utf-8python2虽然指定了编码,但还是不能很好地处理中文,在终端输出、文件读写、json处理等都难免遇到问题 。要解决各种编码问题,需要明确当前编码是什么,python编码的相关特性,数据来源是什么编码,数据输出又是什么编码 。
三、起点-python2打印输出中文我们在python2文件开头设置了编码方式为utf-8,如果cmd终端字符编码不是utf-8,要正常打印输出中文,还 需要将字符串先解码,再编码成终端的编码格式输出  。
比如,中文windows系统的cmd终端默认是gbk中文编码,chcp查看活动代码页编号是936,也就是gbk编码,要正常输出中文,字符串需要先解码,再编码成终端的gbk格式打印,如下 。
# -*- coding: UTF-8 -*-#python2import sysprint("中文".decode('utf-8').encode(sys.stdout.encoding))#文件开头已经指定默认编码为utf-8,但是终端是gbk,所以需要先decode('utf-8') 再 encode(sys.stdout.encoding)四、特性初识-python2/python3的unicode类型python2与python3在定义unicode类型时是通用的 。
#定义unicode类型u = u'中文'u = u"中文"u = u'''中文'''u = u"""中文"""我们知道unicode是通用的,所以无论使用python2还是python3执行如下代码时均不会出现乱码 。
print(u"中文")print(u'\u4e2d\u6587')#均输出中文所以前面python2 打印输出 的问题其实可以简写 。
print("中文".decode('utf-8'))#"中文".decode('utf-8')是unicode类?五、区别-python2/python3的str、bytes类型python2与python3在定义str、bytes类型时是通用的 。
#定义str类型s = 'test's = "test"s = '''test'''s = """test"""?#定义bytes类型b = b'test'b = b"test"b = b'''test'''b = b"""test"""首先,bytes类型是字节序列,一个事实上的bytes类型每个元素就是一个字节。
打开一个gbk编码的文本,可以看到其对应十六进制字符码 。

理解Python的编码问题

文章插图
 
utf-8编码的文本,字符码则不同 。可以看到, 能表示更多字符的编码标准,需要更多的字节来表示字符  。
理解Python的编码问题

文章插图
 
首先查看如下python2代码运行情况 。
理解Python的编码问题

文章插图
 
可以看到,python2处理str和bytes时是混用的,可以进行+运算,但它们都是字节序列 。python2没有将str和bytes型数据做明显的区分,是一种隐式的混用,并且python2处理str类型时优先将其视为bytes。事实上str.decode是bytes.decode,从而转换成unicode 。str/bytes/unicode三者关系:str(bytes)—decode—>unicode—encode—>str(bytes)。
不同于python2,python3对str和bytes型数据作了明显区分,str表示文本,默认就是原生unicode的utf-8编码格式,bytes型数据就表示二进制数据,用下标取bytes类型的单个元素返回的是int类型,而在python2中用下标取bytes类型的单个元素返回的还是bytes 。bytes/str/unicode三者关系:bytes—decode—>str(unicode)—encode—>bytes,不能像python2那样string.decode 。


推荐阅读