justou
2016-06-10 21:51:30 +08:00
也写个简单总结吧
unicode 字符集说白了就是 0 到 0x10ffff 这一串数字(0 到 1114111),也叫码点, 比如汉字"中", python 中的 unicode 表示为 u'\u4e2d', \u 是转义字符, 码点是 0x4e2d(十进制为 20013). 这些数字需要转化成字节序列(0-255)在内存中表示时, 就要有一个规则将 unicode 码点(比如 0x4e2d)转换为字节序列, 这个规则就是编码, 这个过程反过来时的规则叫做解码, 另外只有 UTF 家族(UTF-8, UTF-16,...)的编码器才能将任意 unicode 码点完全正确的编码为字节序列.
python 处理各种编码的一个准则: early decode, always unicode, late encode.
early decode:
在获取外部输入时(文件, 终端, 网络...)尽早的将其解码为 unicode. 如果已知外部输入的编码时, 就用那个编码将输入 decode 就是; 如果不知道的话就只能靠统计的方法检测其编码了, 没有其它完全可靠的算法(但是 utf 编码的可以直接检测 BOM), 比如大多数浏览器自动检测编码就是靠统计, 最后以某个大概率统计出具体编码, python 的一个扩展库 chardet 也是基于统计, 如果是写爬虫的话, chardet 几乎是一个必须的库吧(requests 都直接把 chardet 放在自己的包里面了), 如果是读取本地文件, py2 要依赖标准库的 codecs 解码, py3 的 open 函数自带解码参数
always unicode:
程序内部处理过程中都统一为 unicode
late encode:
程序处理完, 需要将其输出了, 无论输出在终端是还是在文件, 都是给人看的, 需要将 unicode 码点转换为字节序列, 比如说简中 windows 的控制台吧, 默认代码页是 cp932, 编码数大概是 23,940 个(跟 unicode 的 1114112 个比较下就知道为啥好多字符都不能显示在控制台了), 显示在控制台一般能起个简单观测的作用, 可以简单的 ignore 掉不能显示的字符
eg:
---------------------------------------------------------------------------------------------------------------------------------------------
# -*- encoding = utf-8 -*-
# 上面这一行的作用是提示 python 虚拟机, 它将要读取的这个代码文件是 utf-8 编码的.因为这里面会有英语以外的字符
# 这不是强制的, 如果虚拟机发现不是 utf-8 编码的, 会用默认的 ascii 读取该代码文件, 于是有不是英文的字符就会报错
# 当然你也必须保存为 utf-8, 而且是有 BOM(Byte Order Mark)的 utf-8 文件, 试试用其它编辑器改成 No BOM 或者
# 其它编码, 虚拟机检测不到文件的 BOM, 也转为使用 ascii 解码并读取该文件
import locale
local_encoding = locale.getpreferredencoding() # 获取控制台默认编码, 不一定是 cp932 呀
print local_encoding
alice = u"アリス・マーガトロイド"
# 这个日文的点・在 cp936 的控制台是显示不出来的, 如果想在控制台显示这个字符串,
# 可以在编码时选择 ignore 不能编码的字符,或者 replace(默认使用?替换)
try:
print alice
except Exception as e:
print e
print alice.encode(local_encoding, errors="ignore")
---------------------------------------------------------------------------------------------------------------------------------------------
用 windows 终端运行看看吧, 当然在 IDE 中 print alice 可能能完整显示, 因为输出被重定向了
------------------------------------------
在 python 自带的 IDLE 中运行的结果:
cp936
アリス・マーガトロイド
アリスマーガトロイド
IDLE 中输出被重定向, 点正确显示
使用 cp936 编码后点被 ignore 了
----------------------------------------
控制台运行的结果:
cp936
'gbk' codec can't encode character u'\u30fb' in position 3: illegal multibyte sequence
アリスマーガトロイド
编码失败
忽略不能编码的码点
输出到文件跟输出到控制台是一样的, 都是需要某个具体编码的地方, 当然这时可以指定能完全编码 unicode 的 UTF 系列编码器完全无误的记录下来.
文本的编码解码可以类比音视频的编码解码, 比如用一个音乐播放器播放视频, 解码器给错, 当然不能播放,decode error; 压制视频的时候, 给 video 指定一个 audio 的编码器, encode error