zoukankan      html  css  js  c++  java
  • python与编码

    编码的概念

      学习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类型为bytes
    name2 = u'杰夫'   #将字符串类型改为Unicode
    print  repr(name)
    print  repr(name2)
    
    
    运行结果
    'xbdxdcxb7xf2'
    u'u6770u592b'

        在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)
    运行结果
    <type 'unicode'>
    <type 'str'>
    'xe6x9dxb0xe5xa4xab'  #str字符串类型的bytes数据
    u'u6770u592b'             #Unicode字符串类型的Unicode数据
    u'u6770u592b'             #str字符串类型解码成Unicode数据
    'xe6x9dxb0xe5xa4xab'  #Unicode字符串类型编码成bytes数据

    python3的string编码

        python3中默认的编码方式是utf-8.

    name = b'jeff'
    name2 = '杰夫'
    print(type(name))
    print(repr(name))
    print(type(name2))
    print(repr(name2))
    运行结果
    <class 'bytes'>
    b'jeff'
    <class 'str'>
    '杰夫'

        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))
    运行结果
    <class 'bytes'>
    <class 'str'>
    <class 'str'>
    <class 'bytes'>
    b'jeff'                         #bytes类型字符串存储的bytes数据
    '杰夫'                           #str类型字符串存储的Unicode数据
    'jeff' #bytes类型字符串解码成Unicode数据 b'xe6x9dxb0xe5xa4xab' #str类型字符串编码城bytes数据

        简单的总结一下编码bytes数据是为了方便传输与存储,而Unicode数据方便了显示,python3比python2更加清晰化了字节与字符的界限,python3取消了python2中的不同类型字符串的拼接。

        因为编码方式的不同经常会出现下面这种情况。

        在python中写一个小程序,

    #coding=utf8
    print('杰夫')
    

      在windows终端打开此文件。

    这里显示出一堆乱码,这是为什么呢?

    因为我的python3默认编码方式是utf-8,而我的windows终端默认解码方式是GBK,lianxi1.py这个文件内容在内存中以utf-8的编码方式写入硬盘,在cmd中执行时,cmd软件默认解码方式是GBK,用GBK的方式去解码utf-8的二进制数据,解码出来的就是一堆乱码,所以解决方法就是要么让cmd使用utf-8的方式来解码,否则就只能让python解释器用GBK方式将文件内容编码存入硬盘。

    #coding=GBK
    print('杰夫')

       http://www.cnblogs.com/yuanchenqi/p/5956943.html苑昊老师的博客里对于字符编码的详细解释写的非常棒,可以进行进一步参考。

  • 相关阅读:
    MySql为查询结果添加前、后缀
    SQLHelper类
    OracleHelper类
    C#在sql中使用變量訪問Oracle數據庫
    转-调用HTMLTestRunner生成的报告中不能显示用例中print函数的输出
    HTMLTestRunner优化:带截图、饼图、失败重跑
    【转】如何成功安装旧版本火狐,成功安装firebug和firepath插件
    【转】Selenium 加载Chrome/Firefox浏览器配置文件
    mac查看python安装路径
    requests模拟上传照片
  • 原文地址:https://www.cnblogs.com/Jeffding/p/7102262.html
Copyright © 2011-2022 走看看