美文网首页程序猿日记程序员机器学习与数据挖掘
编程笔记 | 字符编码、Python字符串以及常见异常

编程笔记 | 字符编码、Python字符串以及常见异常

作者: 胖三斤66 | 来源:发表于2018-04-12 10:22 被阅读80次

    在讲 Python 字符串之前先了解一下常用的字符编码

    常用三种字符编码发展

    常用的三种字符编码与特点:

    1. ASCII码 :最早
    2. Unicode : 把所有语言都统一到一套编码
    3. UTF-8 : 相对于Unicode节省空间,并兼容ASCII码

    发展由来:
    最早的编码是「ASCII码」,其编码范围为 0 - 127,即只能存放127个字符,包括了大小写英文字母、数字和一些符号。每个字符占一个字节。

    这样,ASCII 码只能处理英文,那么其他语言字符呢?

    其他语言字符编码则是在 ASCII 码基础上扩展。例如,要处理一个中文字符一个字符是不够的,且不能与ASCII码冲突,所以中国制定了「GB2312码」,把中文编进去。但又由于全世界有很多语言,如果都各编各的话,在互相交流就容易产生乱码。

    此时「Unicode」把所有语言都统一到一套编码。Unicode字符通常占 2 个字节或以上。Unicode至少占用 2 个字节,这又带来了问题:原本ASCII码中占 1 个字节的A到Unicode要占 2 个字节,就浪费了一倍的存储空间。

    为了节省空间,人们又发明了可变长「UTF-8」,它对一个不同范围的
    Unicode 字符使用不同长度的编码,如英文字母被编码为 1 个字节,汉字通常为 3 个字节。可以看出,UTF-8包含了ASCII码。故此,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

    三种编码的对比

    最后,用一幅图来总结这三种编码演变过程


    常用三种字符编码演变过程

    计算机系统通用的字符编码工作方式

    现在计算机系统通用的字符编码工作方式:

    在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,一般就转换为UTF-8编码。

    举个例子,当你记事本选择UTF-8格式保存时,记事本的内容按照UTF-8编码存放在硬盘中。而当你在编辑记事本内容(即内容被读取到内存中)
    时,UTF-8的字符会被转换Unicode字符放在内存中。

    Python2.x 字符串

    因为 Python 诞生比 Unicode 早,所以一开始 Python 只支持 ASCII字符串,后面才加上Unicode字符串。故此,Python2.x的字符串的编码方式有两种 :

    1. 按ASCII编码,它是字符串默认的编码方式,对应的字符串类型是str
    2. 按Unicode编码,对应的字符串类型是unicode

    举个例子

    >>>type('hello')
    <type 'str'>
    >>> type(u'hello')
    <type 'unicode'> 
    

    正因为两种编码方式共存并且我们经常会用到中文字符不包含在 ASCII
    中,稍有转换不对就会抛出异常。以下两个异常最为多见:

    第一种:「SyntaxError」: Non-ASCII character '\xe4' ...

    问题描述
    举个例子,在一个 .py 文件中

    print u'中'
    
    SyntaxError: Non-ASCII character '\xe4' in file E:\test.py on line 1, 
    but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
    

    问题产生的原因
    根据官方文档的解释是, Python2.x 的解释器默认按 ASCII 编码去读取源代码,而u'中'并不是 ASCII 编码的字符串,所以解释器没法正确读取源代码。

    总之,「如果解释器读取源代码按照默认编码方式 ASCII 的话,文件存在中文字符就会报错」

    解决方法
    官方文档给出的解决方案是在 .py 文件的第一行或第二行加上

    # -*- coding: utf-8 -*-
    

    用于申明 Python2.x 解释器按 UTF-8 编码读取文件。

    PS :
    这里需要注意一下,源代码文件按照 UTF-8 格式存储,仅代表在硬盘中字符按 UTF-8 编码存储。并不是指定 Python解释器读取源代码的编码方式。
    但如果不按照 UTF-8 格式存储文件,可能下次打开文件,文件中的中文字符会变成乱码。

    第二种:「UnicodeEncodeError」: 'ascii' codec can't encode characters ...

    问题描述
    举个例子,在一个 .py 文件中

    # -*- coding: utf-8 -*-
    str(u'中')
    
    Traceback (most recent call last):
     File "E:\test.py", line 3, in <module>
       str(u'中文')
    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
    

    问题产生的原因
    从异常的提示信息,知道了因为 ASCII 编解码器不能编码 Unicode 字符。
    上面说到,Python2.x str() 的编码是 ASCII, ASCII 编解码器只通过范围0-127的字符,超过范围的字符就会报错。其中 u'中' 是 Unicode 且占2个字节,已经超过了127的范围。

    总之,「如果存放将 Unicode 字符串强行转换为默认的字符串(str类型)的时候,就会报这种异常」

    解决方案

    # -*- coding: utf-8 -*-
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    str(u'这')
    

    通过 sys 模块修改解释器默认编码格式后,将默认编码格式也改成 UTF-8, 就变成 Unicode 转 UTF-8,此时转换就没问题了。
    放在这个例子中,str是默认的字符串类型,编码方式是 ASCII,修改了解释器的默认编码格式,str的编码方式也跟着改变。

    Python3.x 字符串

    在 Python3 中,默认字符串编码改为了 Unicode,这样使得 Python 更好地支持多语言了。同样, Python3 依旧支持两种字符串,

    1. Unicode 字符串,是默认的编码格式,不需要在前面加u,对应的类型是 str
    2. Byte 字符串,编码格式是 ASCII,需要在字符串面前加b,例如b'abc'

    需要注意的是,
    默认情况下,Python 源文件是 UTF-8 编码。在此编码下,全世界大多数语言的字符可以同时用在字符串、标识符和注释中 — 尽管 Python 标准库仅使用 ASCII 字符做为标识符,这只是任何可移植代码应该遵守的约定。如果要正确的显示所有的字符,你的编辑器必须能识别出文件是 UTF-8 编码,并且它使用的字体能支持文件中所有的字符。 Python3 源文件的第一行或者第二行依旧需要加上

    # -*- coding: utf-8 -*-
    

    通过此声明,源文件中所有的东西都会被当做用 encoding 指代的 UTF-8 编码对待。

    相关文章

      网友评论

        本文标题:编程笔记 | 字符编码、Python字符串以及常见异常

        本文链接:https://www.haomeiwen.com/subject/iujwhftx.html