• python编码encode decode(解惑)


    关于python 字符串编码一直没有搞清楚,今天总结了一下。

    Python 字符串类型

    Python有两种字符串类型:str 与 unicode。

    字符串实例

    # -*- coding: utf-8 -*-
    
    # 这个是 str 的字符串
    s = '关关雎鸠'
    
    # 这个是 unicode 的字符串
    u = u'关关雎鸠'
    
    print isinstance(s, str)      # True
    print isinstance(u, unicode)  # True
    
    print s.__class__   # <type 'str'>
    print u.__class__   # <type 'unicode'>
    
    

    前面的申明表明,上面的 Python 源代码由 utf-8 编码,由于代码中有中文,所以需要加上。

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

    两种python字符串类型之间的转换

    # 从 str 转换成 unicode
    print s.decode('utf-8')   # 关关雎鸠
    
    # 从 unicode 转换成 str
    print u.encode('utf-8')   # 关关雎鸠
    

    为什么从 unicode 转 str 是 encode,而反过来叫 decode?

    因为 Python 认为 16 位的 unicode 才是字符的唯一内码,而大家常用的字符集如 gb2312,gb18030/gbk,utf-8,以及 ascii 都是字符的二进制(字节)编码形式。把字符从 unicode 转换成二进制编码,当然是要 encode。

    反过来,在 Python 中出现的 str 都是用字符集编码的 ansi 字符串。Python 本身并不知道 str 的编码,需要由开发者指定正确的字符集 decode。

    如果用错误的字符集来 encode/decode 会怎样?

    # 用 ascii 编码含中文的 unicode 字符串
    u.encode('ascii')  # 错误,因为中文无法用 ascii 字符集编码
                       # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
    
    # 用 gbk 编码含中文的 unicode 字符串
    u.encode('gbk')  # 正确,因为 '关关雎鸠' 可以用中文 gbk 字符集表示
                     # 'xb9xd8xb9xd8xf6xc2xf0xaf'
                     # 直接 print 上面的 str 会显示乱码,修改环境变量为 zh_CN.GBK 可以看到结果是对的
    
    # 用 ascii 解码 utf-8 字符串
    s.decode('ascii')  # 错误,中文 utf-8 字符无法用 ascii 解码
                       # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
    
    # 用 gbk 解码 utf-8 字符串
    s.decode('gbk')  # 不出错,但是用 gbk 解码 utf-8 字符流的结果,显然只是乱码
                     # u'u934fu51b2u53e7u95c6u5ea8u7b2d'
    

    陷阱

    这要提到处理 Python 编码时容易遇到的陷阱。

    字符串连接

    
    # -*- coding: utf-8 -*-
    # file: example2.py
    
    # 这个是 str 的字符串
    s = '关关雎鸠'
    
    # 这个是 unicode 的字符串
    u = u'关关雎鸠'
    
    s + u  # 失败,UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
    
    

    在进行同时包含 str 与 unicode 的运算时,Python 一律都把 str 转换成 unicode 再运算,当然,运算结果也都是 unicode。

    由于 Python 事先并不知道 str 的编码,它只能使用 sys.getdefaultencoding() 编码去 decode。sys.getdefaultencoding() 的值一般是 'ascii'。
    显然,如果需要转换的 str 有中文,一定会出现错误。

    % 运算的结果

    # 正确,所有的字符串都是 str, 不需要 decode
    "中文:%s" % s   # 中文:关关雎鸠
    
    # 失败,相当于运行:"中文:%s".decode('ascii') % u
    "中文:%s" % u  # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
    
    # 正确,所有字符串都是 unicode, 不需要 decode
    u"中文:%s" % u   # 中文:关关雎鸠
    
    # 失败,相当于运行:u"中文:%s" % s.decode('ascii')
    u"中文:%s" % s  # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
    

    在 Python 3 已经取消了 str,让所有的字符串都是 unicode ——这也许是个正确的决定。

    总结

    string 模块已经停止了更新,只保留了 ASCII 码的支持,string 模块已经不推荐使用,在任何需要跟 Unicode 兼容的代码里都不要再用该模块,Python 保留该模块仅仅是为了向后兼容.

    Python 把硬编码的字符串叫做字面上的字符串,默认所有字面上的字符串都用 ASCII 编码,可以通过在字符串前面加一 个'u'前缀的方式声明 Unicode 字符串,这个'u'前缀告诉 Python 后面的字符串要编码成 Unicode 字符串 .

    内建的 str()函数和 chr()函数并没有升级成可以处理 Unicode.它们只能处理常规的 ASCII 编码字符串,如果一个 Unicode 字符串被作作为参数传给了 str()函数,它会首先被转换 成 ASCII 字符串然后在交给 str()函数.

    如果该 Unicode 字符串中包含任何不被 ASCII 字符串支 持的字符,会导致 str()函数报异常.同样地,chr()函数只能以 0 到 255 作为参数工作.如果你 传给它一个超出此范围的值(比如说一个 Unicode 字符),它会报异常.

    新的内建函数 unicode()和 unichar()可以看成 Unicode 版本的 str()和 chr().Unicode() 函数可以把任何 Python 的数据类型转换成一个 Unicode 字符串,如果是对象,并且该对象定义 了__unicode__()方法,它还可以把该对象转换成相应的 Unicode 字符串.

    处理字符串的准则:

    • 程序中出现字符串时一定要加个前缀u.
    • 不要用str()函数,用unicode()代替.
    • 不要用过时的 string 模块 -- 如果传给它的是非 ASCII 字符,它会把一切搞砸。
    • 不到必须时不要在你的程序里面编解码 Unicod 字符.只在你要写入文件或数据库或者网络时,才调用 encode()函数;相应地,只在你需要把数据读回来的时候才调用 decode() 函数.

    参考

    http://in355hz.iteye.com/blog/1860787

    《python核心编程 第二版》

  • 相关阅读:
    [题解]小B的询问-莫队水题
    [学习笔记]莫队学习笔记[未完待续]
    ffmpeg设置超时时间
    python signal
    pydantic库使用文档
    rtmp及直播流相关资料
    ffmpeg 将视频转换成m3u8视频
    nginx stop失败问题
    linux使用ssh远程登录服务器
    解决Fcitx输入法文字候选无前端问题
  • 原文地址:https://www.cnblogs.com/lanyangsh/p/10011758.html
Copyright © 2020-2023  润新知