Python unicode 三明治
大家在使用 python 读取文件或者处理 http 请求结果时,应该经常会遇到,特别是文件中有某些特殊字符,比如非英语的其他语种或者特殊数学符号等:
UnicodeDecodeError
报错以 b 开头的字符,类似
b'caf\xc3\xa9'
这里就涉及到 python 中对字符的表示,python3 中对字符的表示分为 str 和 bytes(就是 b 开头的)。str 可以认为是人类可读的文本,bytes 字节码就是计算机能识别字节码(0/1)。
而 str 文本如何映射到计算机能识别的字节码?最早的 ASCII 编码格式将常用的英文字符表示成一系列数据码点,比如 a 用 97 表示,二进制为 0110001。但是 ASCII 使用的码点智能表示 0 到 127 的码点,其他的特殊无法表示,比如中文或者法语等。
这时 unicode 标准就逐渐完善来解决不同类型的字符表达,比如用 16bits(2 个字节)来表示汉字。一个 unicode 码点由一个 U+前缀加上 4,5,或 6 个 16 进制数字构成。在 python3 中,str 存储的是 unicode 字符,但是在网络 IO 中都是以字节形式进行传输的,所以 Unicode 标准定义了一系列编码标准用来将 unicode 编码为 bytes 用以计算机的存储和传输。这些 unicode 编码就是我们熟悉的 utf-8,gb2312 等编码格式。
从上面的代码可知:
同一个字符,不同的编码格式编码出来的码点是不一样(如 utf8 和 utf16),é在 utf8 和 utf16 编码不一样
而不同的编码能力范围是有限制,比如 ascii 是编码不了é;
同时编码和解码的格式要一致才能正确解码
这里值得一提的是,python 进行业务处理的时候,Ned Batchelder 在 PyCon2012 上的讲座建议,在进行业务逻辑时,处理的都是可视的文本字符,即 unicode 三明治,也就是进入和输出业务要做好转换,中间的格式保持不变,避免不必要的错误。(图片来自网络,如有侵权联系删除)
另外,有一个问题就是在进行编码 encode 之后,在 decode 为可读文本时,必须知道 encode 的编码格式,两者必须一致才能正确解码,否则就会出现某些字符无法正确解码UnicodeDecodeError
,更遗憾的是,你无法通过查看字节码来判断是哪一种编码,只能猜测。
版权声明: 本文为 InfoQ 作者【AIWeker-人工智能微客】的原创文章。
原文链接:【http://xie.infoq.cn/article/be8a352b8acc65978dc908d38】。文章转载请联系作者。
评论