zoukankan      html  css  js  c++  java
  • 从Python的角度来看编码与解码

    导语:

    Python2和Python3中,因为默认字符集的不同而造成的麻烦,简直是程序员的梦魇!要彻底告别这个麻烦,就需要从本质上来理解编码和解码。

    为什么要有编码?

    对于不会英文的中国人来说,将英文翻译成中文,这个就叫做解码;而将中文翻译成英文,自然就是编码了!

    这个道理在计算机中同样适用。

    计算机只能识别0和1,任何文字对于计算机来说,就是0和1的排列组合。但是我们人类哪看得懂这种0和1的排列组合!

    自然就需要将0和1的文字转换为我们能看得懂的文字,比如中文,英文等。

    而这种0和1到文字的映射,就叫做解码;文字到0和1的映射自然就是编码了!

    有了映射关系,自然就需要有个类似“表格”的东西,来记录这种映射关系了!这个“表格”就是我们常说的字符集(也叫编码集,简称编码),比如ascii编码,utf-8字符集。

    习惯上,我们把人类能看懂的文字叫做字符,对应的计算机能看得懂的文字叫做字符编号(也就是字节流),而字符集就是这种字符和字符编号的映射。

    为什么会有乱码?

    上面我们说到,字符集有多种,那么问题来了。

    比如,在编码时,我采用utf-8字符集进行文字到0和1的映射,但是解码时,又采用gbk的字符集进行0和1到文字的映射,

    2种字符集的映射规则是不一样的!结果自然就是乱码!

    这就像我买了张三家的锁,却用李四家配的钥匙来开门,能开门就见鬼了!

    (其实对于计算机来说,根本没有乱码这一说法!对于特定的字符,0和1的排列组合是唯一不变的,变得是映射后的文字。)

    关于文件编码

    不知道有没有人有过这样的疑问,CPU一个只能运算0和1的器件,是如何能够处理文本、图片、视频和声音这些资源的?

    其实这就要讲到文件编码。

    以下文字来自知乎网友的解答:

    作者:DJ Hitori
    链接:https://www.zhihu.com/question/27805272/answer/74539468
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    文字:
    
    有若干种标准可以用8~16位二进制数表示一个字符,比如用8位数表示英语字母数字的ASCII,用16位数表示几乎所有语言所有字符的Unicode等。以ASCII为例,这个标准用01000001这个数表示大写的A,于是某个文字处理软件看到这个数字知道这是A,然后向一个字体文件询问字母A长什么样,然后把它画在屏幕上,你就看到了A。
    
    图像:
    
    最简单的格式叫“位图”(BMP),用24位二进制数表示图像中的一个点,这24位数中8位表示这个点有多少红色,8位表示多少绿色,8位表示多少蓝色,三种原色组合起来就可以表示几乎所有的颜色。很多个24位数连在一起,就是很多个点,于是就组成了一幅图像。除此以外还有其他格式以更少的数字表示同样多的图像内容,如JPG、PNG等。
    
    声音:
    
    声音是波,是数学上的连续函数,而计算机无法理解连续函数,所以每秒取样44100次,把1秒的声音变成44100个数字记录下来,这是录音的过程。回放时,把这些数字交给声卡,声卡控制喇叭按照这些数字表示的幅度震动,就发出了声音。同样,除了44100个数字(这是WAV格式)以外还有其他格式以更少的数字表示同样多的声音,如MP3、OGG等。
    
    视频:
    
    既然有了图像和声音的标准,那么每秒钟24~60幅图像再加上1秒钟的声音就组成了1秒钟的视频内容。不过这种做法的数据量异常庞大,所以没人这么干,科学家们发明了各种编码方式以非常非常少(相对于未压缩)的数字表示同样多的视频内容,如H.264等。
    
    各种软件控制CPU按照各种标准理解了多媒体内容后,计算出屏幕上每一个点应该是什么颜色(和位图一样),然后把这些计算结果交给显卡,显卡把这一堆数字表示的颜色画到屏幕上,这叫做一次刷新。一般来说每秒刷新60次,这样你就流畅地看到了你所打开的多媒体内容。

    了解了编码和解码的大环境之后,再来看看Python中的编码和解码:

    字符串类型

    Python2中字符串类型有2种,unicode和str。 

    其中普通字符串为unicode形式,字节流为str。

    >>> s = '中国'
    >>> s
    'xe4xb8xadxe5x9bxbd'
    >>> u = u'中国'
    >>> u
    u'u4e2du56fd'
    >>> type(s)
    <type 'str'>
    >>> type(u)
    <type 'unicode'>

    Python3中字符串类型只有str一种;

    另外需要注意的一点就是:python3中str即Unicode,3中的字符串默认都是Unicode形式。

    >>> s = '中国'
    >>> s
    '中国'
    >>> type(s)
    <class 'str'>
    >>> u = u'中国'
    >>> u
    '中国'
    >>> type(u)
    <class 'str'>

    默认字符集

    Python2中默认字符集为ascii,其中默认中文字符集为utf-8。

    >>> sys.getdefaultencoding()
    'ascii'

    Python3中,无论什么文,默认字符集为utf-8。

    >>> sys.getdefaultencoding()
    'utf-8'

    关于编码和字节流

    编码的结果为字节流。

    Python2,str即是字节流

    >>> u.encode('gbk')
    'xd6xd0xb9xfa'
    >>> u.encode('utf-8')
    'xe4xb8xadxe5x9bxbd'
    >>> s
    'xe4xb8xadxe5x9bxbd'
    >>> s = b'中国'
    >>> s
    'xe4xb8xadxe5x9bxbd'
    >>> type(s)
    <type 'str'>
    >>> bytes(s)
    'xe4xb8xadxe5x9bxbd'

    Python3,不能够直接定义中文字节流

    >>> s.encode('utf-8')
    b'xe4xb8xadxe5x9bxbd'
    >>> s = b'中国'
      File "<stdin>", line 1
    SyntaxError: bytes can only contain ASCII literal characters.

    关于解码

    解码的结果为str(python3)或者unicode(python2)

    Python2

    >>> s.decode('utf-8')
    u'u4e2du56fd'
    >>> u
    u'u4e2du56fd'

    Python3

    >>> a
    b'xe4xb8xadxe5x9bxbd'
    >>> a.decode()
    '中国'

    检测

    可以通过isinstance()来判断类型

    >>> isinstance(a,str)
    True
    >>> isinstance(b'qq',str)
    True

    关于错误

    1.

    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd6 in position 0: invalid continuation byte

    出现上述错误的原因在于:

    编码时使用的字符集和解码时使用的字符集不一致。

    注意:open()方法,在window下默认的字符集为gbk;Linux下默认字符集是utf-8,所以在window下可能需要指定encoding='utf-8'。

    本地语言环境:locale.getdefaultlocale() 

    当前编码集:sys.getdefaultencoding() 

    Linux下

    >>> import locale
    >>> locale.getpreferredencoding()
    'UTF-8'

    window下

    >>> locale.getpreferredencoding(False)
    'cp936'

    936为代码页编号,表示gbk。

    65001表示utf-8。

    2.

    SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 4-5: truncated UXXXXXXXX escape

    由于转义字符造成的错误。

    如果文件中存在转义字符,比如window下常见的路径名"C:UsersleoDesktop"("U"是转义字符,表示unicode字符),这时就会出现上述错误。

    解决方式有2种:

    1.在转义字符前加上""。

    2.在字符串前加上r,表示使用原始字符串。

    拓展:

    x:当输出的数转换为16进制只有1位时,在前面补0,如 0a,其它情况按照实际情况输出。
    
    x:按照输出数转换为16进制的实际位数输出。
    
    此外,小写x和大写X也有点区别,小写的x输出小写符号的16进制,大写X则输出大写的(主要针对ABCDEF这六位)
  • 相关阅读:
    WPF 得一些问题汇总
    System.Rtti.TRttiObject.GetAttributes 简例
    ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้
    erlang局域网内节点通信——艰难四步曲 (转)
    delphi 单例模式实现
    NotePad++ delphi/Pascal函数过程列表插件
    用Visual C#实现MVC模式的简要方法
    Visual C#常用函数和方法集汇总
    需要Niagara邀请码的伙伴可以联系
    一个通过百度贴吧找到身份证失主的案例(供参考)
  • 原文地址:https://www.cnblogs.com/leomei91/p/7587980.html
Copyright © 2011-2022 走看看