编码的概念
学习python已经半年了,回过头来看编码问题,发现它在我们学习过程中埋了很多雷,不完全搞懂python的编码在学习python的过程中还埋着很多潜在的雷呢。
文件从磁盘到内存的编码
首先,抛开python解释器来说,就一般的应用程序(记事本等)来说,你写的文字还没有保存的时候是以什么形式存在在内存的呢?
是Unicode二进制数据,他是内存编码的一种规范,实际上Unicode编码方式完全解决了全世界的文字编码问题,只是在将内存数据存储到硬盘的时候,Unicode数据占用空间要远大于utf8(编写代码,中文数据出现频率很低),当硬盘不变时,utf8的数据占空间更小,传输更快,所以utf解决了保存和传输数据的问题。
所以,我们保存在磁盘上的数据是什么类型的?
答案是通过某种编码方式编码的bytes字节串。由于历史遗留问题,在utf8之前还有gbk等一些字符编码方式存在。
最早的时候计算机使用的编码规则是ASCII码,ASCII码最早是美国人使用的。ASCII码用一个字节的二进制组来表示一个字符(因为他们只用到26个引文字母和一些符号,最初的ASCII码甚至只用到7个bit位)。
随着计算机的日益普及,ASCII码难以满足世界各地人们的使用,在中国就出现了GB2312与GBK的编码方式,使用两个字节的二进制组表示一个字符(甚至强硬的占用了拉美等国家的最高bit位)。正因为如此,世界各地都使用自己的编码方式,各自的软件都无法兼容了,所以就出现了万国码。
万国码(Unicode)覆盖了全世界所有的文字,这也太强大了,那我们使用万国码不是很方便吗?但是对于美国人来说,他们只需要使用一个字节就可以表示所有的字符,而现在却平白无故多出一个字节,这使得内存与硬盘浪费了空间,所以Unicode优化成了现在的utf-8格式。utf-8是可变长的编码方式,所以现在开发倾向于使用这种编码方式。但是现在依然很多地方在使用GBK,ASCII等编码方式,所以对于编码我们需要详细的了解。
回到应用程序上来,当我们执行保存文件的时候,应用程序有默认的编码方式将内存中的Unicode二进制数编码成bytes类型存储到硬盘,当我们再次打开应用程序的时候,它又以同样的编码方式将硬盘上的bytes数据解码成Unicode数据存放到内存,我们就可以以明文方式看到数据了。
utf8这么好为什么我们内存中不使用utf8格式存放呢,一句话就是utf8不能直接转换成gbk等其他数据,但是Unicode可以直接编码成gbk等格式数据。
Unicode与utf8的关系:
Unicode是内存编码表示方案(是规范),而UTF是如何保存和传输Unicode的方案(是实现)这也是UTF与Unicode的区别。
Unicode进行明文与二进制之间的转换,utf8进行二进制与二进制之间的数据转换打印unicode数据就会显示相应的明文(包括英文和中文)。
python解释器与我们上面说的记事本程序的数据编码解码很类似。
当我们保存的的时候,文件就以pycharm默认的编码方式保存到了磁盘;关闭文件后再打开,pycharm就再以默认的编码方式对该文件打开后读到的内容进行解码,转成unicode到内存我们就看到了我们的明文;(这个过程使用记事本也可以完成,在cmd中完成运行)
而如果我们点击运行按钮或者在命令行运行该文件时,py解释器这个软件就会被调用,打开文件,然后解码存在磁盘上的bytes数据成unicode数据,这个过程和编辑器是一样的,不同的是解释器会再将这些unicode数据翻译成C代码再转成二进制的数据流,最后通过控制操作系统调用cpu来执行这些二进制数据,整个过程才算结束。
以上就是完整的文件的编码,我们下面讲的python2与python3的字符串编码是在cpu执行程序时的存储状态,是另外一个过程,不要混淆!
python2的string编码
python2中默认编码方式是ASCII码。
name = '杰夫' #str类型为bytesname2 = u'杰夫' #将字符串类型改为Unicodeprint repr(name)print repr(name2)运行结果'\xbd\xdc\xb7\xf2'u'\u6770\u592b'
在python2中str字符串类型在内存中存的是bytes类型,Unicode类型字符串存储的是Unicode数据。
name = '杰夫' #name为字节数据类型name2 = u'杰夫' #name为unicode数据类型name3 = name.decode('utf8')name4 = name2.encode('utf8')print type(name3)print type(name4)print repr(name)print repr(name2)print repr(name3)print repr(name4)运行结果'\xe6\x9d\xb0\xe5\xa4\xab' #str字符串类型的bytes数据u'\u6770\u592b' #Unicode字符串类型的Unicode数据u'\u6770\u592b' #str字符串类型解码成Unicode数据'\xe6\x9d\xb0\xe5\xa4\xab' #Unicode字符串类型编码成bytes数据
python3的string编码
python3中默认的编码方式是utf-8.
name = b'jeff'name2 = '杰夫'print(type(name))print(repr(name))print(type(name2))print(repr(name2))运行结果b'jeff' '杰夫'
python3中str字符串类型在内存中存的是Unicode数据,bytes类型字符串存储的是bytes数据。
name = b'jeff'name2 = '杰夫'name3=name.decode('utf8')name4=name2.encode('utf8')print(type(name))print(type(name2))print(type(name3))print(type(name4))print(repr(name))print(repr(name2))print(repr(name3))print(repr(name4))运行结果b'jeff' #bytes类型字符串存储的bytes数据'杰夫' #str类型字符串存储的Unicode数据 'jeff' #bytes类型字符串解码成Unicode数据b'\xe6\x9d\xb0\xe5\xa4\xab' #str类型字符串编码城bytes数据
简单的总结一下编码bytes数据是为了方便传输与存储,而Unicode数据方便了显示,python3比python2更加清晰化了字节与字符的界限,python3取消了python2中的不同类型字符串的拼接。
因为编码方式的不同经常会出现下面这种情况。
在python中写一个小程序,
#coding=utf8print('杰夫')
在windows终端打开此文件。
这里显示出一堆乱码,这是为什么呢?
因为我的python3默认编码方式是utf-8,而我的windows终端默认解码方式是GBK,lianxi1.py这个文件内容在内存中以utf-8的编码方式写入硬盘,在cmd中执行时,cmd软件默认解码方式是GBK,用GBK的方式去解码utf-8的二进制数据,解码出来的就是一堆乱码,所以解决方法就是要么让cmd使用utf-8的方式来解码,否则就只能让python解释器用GBK方式将文件内容编码存入硬盘。
#coding=GBKprint('杰夫')
http://www.cnblogs.com/yuanchenqi/p/5956943.html苑昊老师的博客里对于字符编码的详细解释写的非常棒,可以进行进一步参考。