python编码问题
一、编码历史:
1、ASCII(主要用于显示现代英语和其他西欧语言,其最多只能用 8 位来表示(一个字节),即:2**8 = 256-1,所以,ASCII码最多只能表示 255 个符号。
2、为了处理汉字,程序员设计了用于简体中文的GB2312,但GB2312 支持的汉字太少,之后扩展规范为GBK,之后为GB18030(手机、MP3一般只支持GB2312)。从ASCII、GB2312、GBK 到GB18030,这些编码方法是向下兼容的。GB2312、GBK、GB18030都属于双字节字符
3、因为ASCII码无法将世界上的各种文字和符号全部表示,所以,需要一种可以代表所有字符和符号的编码,即:Unicode(统一码、万国码、单一码),它为每种语言中的每个字符设定了统一并且唯一的二进制编码,规定字符和符号最少由16位来表示(2个字节),即:2 **16 = 65536。
4、UTF-8,是对Unicode编码的压缩和优化,它是可变长度编码,很好的节省了空间。winx的操作系统安装时是默认的gbk编码,而linux操作系统默认的是utf8编码。
二、py3的编码:
Py3有两种数据类型:str和bytes,str类型存unicode数据,bytse类型存bytes数据。Python 3对文本和二进制数据作了更为清晰的区分,不再会对bytes字节串进行自动解码。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,这使两者的区分特别清晰。你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然)。
在py3中encode,在转码的同时还会把string 变成bytes类型,decode在解码的同时还会把bytes变回string
import json
s = '苑昊'
print(type(s) )#<class 'str'>
print(json .dumps(s) )#"\u82d1\u660a"
b=s.encode('utf-8')
print(type(b))#<class 'bytes'>
print(b)#b'\xe8\x8b\x91\xe6\x98\x8a'
u=b.decode('utf-8')
print(type(u) )#<class 'str'>
print(u)#苑昊
print(json .dumps(u) )#"\u82d1\u660a"
print(len('苑昊'))#2
三、文件从磁盘到内存的编码:
文本编辑器比如word,我们在word上编辑的文字在保存之前数据是通过什么形式存在内存的呢?是unicode数据,这是因为它是万国码,任何字符它都有唯一编码对应,所以兼容性是最好的。
当我们保存了的存到磁盘上的数据是通过某种编码方式编码的bytes字节串。比如utf8——一种可变长编码,很好的节省了空间,还有gbk编码等等。于是,在我们的文本编辑器软件都有默认的保存文件的编码方式,比如utf8,比如gbk。当我们点击保存的时候,这些编辑软件已经"默默地"帮我们做了编码工作。那当我们再打开这个文件时,软件又默默地给我们做了解码的工作,将数据再解码成unicode,然后就可以呈现明文给用户了!所以,unicode是离用户更近的数据,bytes是离计算机更近的数据。
再说程序执行:先明确一个概念:py解释器本身就是一个软件,一个类似于文本编辑器一样的软件!现在让我们一起还原一个py文件从创建到执行的编码过程:
打开pycharm,创建hello.py文件,写入
s='苑昊'
print(s)
当我们保存的的时候,hello.py文件就以pycharm默认的编码方式保存到了磁盘;关闭文件后再打开,pycharm就再以默认的编码方式对该文件打开后读到的内容进行解码,转成unicode到内存我们就看到了明文;而如果我们点击运行按钮或者在命令行运行该文件时,py解释器这个软件就会被调用,打开文件,然后解码存在磁盘上的bytes数据成unicode数据,这个过程和编辑器是一样的,不同的是解释器会再将这些unicode数据翻译成C代码再转成二进制的数据流,最后通过控制操作系统调用cpu来执行这些二进制数据,整个过程才算结束。
那么问题来了,我们的文本编辑器有自己默认的编码解码方式,我们的解释器有吗?
当然有,py2默认ASCII码,py3默认的utf8,可以通过如下方式查询
1 2 |
import sys print(sys.getdefaultencoding()) |
常见的编码问题:
cmd下的乱码问题
hello.py
#coding:utf8
print ('苑昊')
文件保存时的编码也为utf8。
思考:为什么在IDE下用2或3执行都没问题,在cmd.exe下3正确,2乱码呢?
我们在winx下的终端即cmd.exe去执行,大家注意,cmd.exe本身也一个软件;当我们python2 hello.py时,python2解释器(默认ASCII编码)去按声明的utf8编码文件,而文件又是utf8保存的,所以没问题;问题出在当我们print'苑昊'时,解释器这边正常执行,也不会报错,只是print的内容会传递给cmd.exe用来显示,而在py2里这个内容就是utf8编码的字节数据,可这个软件默认的编码解码方式是GBK,所以cmd.exe用GBK的解码方式去解码utf8自然会乱码。
py3正确的原因是传递给cmd的是unicode数据,cmd.exe可以识别内容,所以显示没问题。
明白原理了,修改就有很多方式,比如:
print (u'苑昊')
改成这样后,cmd下用2也不会有问题了。
参考:http://www.cnblogs.com/yuanchenqi/articles/5956943.html