添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

字符编码

常用字符编码有 ASCII , GB2312 , Unicode , UTF-8 等,为什么需要这么多不同的编码,又是怎么来的呢?
计算机能够识别的只有二进制的0和1,要处理字母等类型只能转换为类似 01010001 的二进制数字才能处理;人要能够正常阅读,也需要计算机将二进制数转换为对应的字母。那么如何转换,转换的规则和标准又是什么?这就是我们常见的编码所规定的。

ASCII

计算机是美国人发明的,因此最早只有英语中的127个字符(包括大小写字母、数字、特殊符号等)被编码到计算机里,这个编码表就是 ASCII 编码。根据前面一个字节(8比特)最多可以表示 256 个字符,那么对于英文中的100多个字符使用一个字节中的前7位就可以表示。

GBK

英文是可以被计算机识别了,那么中文怎么破?为了解决汉字问题,中国国家标准总局提出了 GB2312 编码,收录了6763个汉字,后来又在此基础上创建了 GBK 编码,收录了27484汉字,同时收录了包括藏文、蒙文等在内的主要少数名族文字。

Unicode

中文使用 GBK 编码,那么对于其他国家的文字如何处理,各个国家都有建立了自己的标准。为了统一标准,统一联盟国际组织提出了 Unicode 编码,该编码将所有语言统一到一套编码。
Unicode标准也在不断发展,最常见的是两个字节表示一个字符(生僻字符可能需要4个字节)。
ASCII Unicode 主要区别:ASCII编码使用1个字节,Unicode编码通常是2个字节。

字母 A 用ASCII编码是十进制的 65 ,二进制的 01000001 ;
字符 0 用ASCII编码是十进制的 48 ,二进制的 00110000 ;
汉字 已经超出ASCII编码范围,用Unicode编码是十进制的 20013 ,二进制的 01001110 00101101 ;
ASCII编码的 A 用Unicode编码,只要在前面补0就可以, A 的Unicode编码是 00000000 01000001

从上面可以看出,假如对英文使用Unicode编码要比ASCII编码多一倍的存储空间,在存储和传输上不方便。
所以本着节约的精神,又出现了把Unicode编码转换为可变长编码的 UTF-8 编码。UTF-8编码把一个Unicode字符根据不同数字大小编码成1-6个字节,常用的英文字母编码成1个字节,汉字通常是3个字节。当传输的文本中包含大量的英文字符时,用UTF-8编码可以节省空间。
上面内容总结一下就是

  • 为处理英文字符,出现了 ASCII 码。
  • 为处理中文字符,出现了 GB2312 GBK
  • 为统一处理不同国家不同语言,出现了 Unicode 编码。
  • 为提高Unicode传输和存储的性能,出现了 UTF-8 ,它是Unicode的一种实现方式。

    python2的字符编码

    python2中默认的字符编码是 ASCII 码,也就是说在处理数据时,若没有指定它的编码类型,默认将会当做ASCII码来处理。当编写的python文件中包含有中文字符时就会报错。
    1
    2
    3
    #!/usr/bin/env python
    s = "是否乱码"
    print(s)

    执行结果
    python-code-default
    根据上述结果可以看到出错原因是python将整个脚本当做ASCII码处理,但是出现的中文 是否乱码 ASCII码无法处理。处理方式很简单,在头部添加一行编码声明。

    1
    2
    3
    4
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    s = "是否乱码"
    print(s)

    执行结果
    pycharm执行
    python-code-utf8-pycharm
    windows命令行执行
    python-code-utf8-cmd
    声明编码方式之后发现在pycahrm执行输出正确信息,但是在windows命令行输出乱码。
    windows命令行默认使用的是 GBK 编码,但是在python脚本中使用的是 UTF-8 ,两边不一致导致出现乱码,只要修改两者一致即可。

    1
    2
    3
    4
    #!/usr/bin/env python
    # -*- coding: GBK -*-
    s = "是否乱码"
    print(s)

    执行结果
    python-code-gbk
    此时可以看到在命令行执行结果显示正确,但是相应的在pycharm执行就会出现乱码的情况。也进一步说明导致乱码就是编码格式不一致。也就是说,当需要操作系统正确输出一个字符时,除了要知道该字符的字符编码,还需要知道自己使用系统的字符编码,两者一致时就不会出现所谓 乱码

    decode()和encode()

    decode()方法将其他编码字符转换成Unicode编码字符。
    encode()方法将Unicode编码字符转换成其他编码字符。
    python-code-encode
    上述命令在pycharm自带的终端执行,其默认字符编码为 UTF-8
    直接输入 s 出现的 '\xe6\x98\xaf\xe5\x90\xa6\xe4\xb9\xb1\xe7\xa0\x81' 为对应的UTF-8字符串。
    使用decode()方法将s转换为unicode编码,此时输入 unicode_s 出现的 u'\u662f\u5426\u4e71\u7801' 为unicode字符串。
    使用encode()方法将unicode_s转换为GB2312编码,此时输入 gb2312_s 出现的 '\xca\xc7\xb7\xf1\xc2\xd2\xc2\xeb' 为gb2312字符串。由于终端为UTF-8编码,所以使用 print gb2312_s 会出现乱码情况。
    在windows终端可以正常输出gb2312编码的字符串。
    python-code-decode
    总结

  • python2中可以直接查看unicode字符串。
  • python2中对于字符编码的转换通过unicode作为中间人进行转换。
  • decode()方法与在字符串前加u的方法实现的效果相同。
    python-code-u

    python2中的列表

    1
    2
    3
    4
    5
    >>> list1 = ["哈哈","ABC"]
    >>> list1
    ['\xb9\xfe\xb9\xfe', 'ABC']
    >>> print list1[0]
    哈哈

    当一个中文的字符出现在列表(或元组或字典)中,它不会被显示为中文而是显示为字符串。但是当该字符窜从列表中取出再使用print时就可以正常显示为中文。
    字符串是所有字符在python2中的本质形态,该字符串是计算机可以理解的,不是通常所说的乱码。在python3中就不存在这种问题了。

    python3的字符编码

    在python3中默认编码方式为 UTF-8 ,所以coding声明可以不用写,但为了兼容python2建议添加。
    python3中字符串类型是 str ,在内存中以Unicode表示,一个字符对应若干个字节。当需要传输或者保存到硬盘时,就需要把 str 变为以字节为单位的 bytes
    以Unicode表示的 str 通过encode()方法可以编码为指定的 bytes

    1
    2
    3
    4
    >>> "ABC".encode('ASCII')
    b'ABC'
    >>> "是否乱码".encode('UTF-8')
    b'\xe6\x98\xaf\xe5\x90\xa6\xe4\xb9\xb1\xe7\xa0\x81'

  • bytes 类型的数据用带 b 前缀的单引号或者双引号表示。
  • bytes 中无法显示为ASCII字符的字节,用 \x## 表示。
    相反,要将 bytes 变为 str ,就需要使用 decode() 方法。
    1
    2
    3
    4
    >>> b'ABC'.decode('ASCII')
    'ABC'
    >>> b'\xe6\x98\xaf\xe5\x90\xa6\xe4\xb9\xb1\xe7\xa0\x81'.decode('UTF-8')
    '是否乱码'

    上面说到的编码问题主要是python2中,请注意区分版本。
    即使在python3中,涉及到 str bytes 转换时,非特殊情况一定要使用 UTF-8 编码。

  •