抛异常 替换成替代字符 跳过
但是在复杂的现实世界中,由于各种不靠谱,我们处理的文本总会出现那么些不和谐因素,比如混合编码。在这种情况下,又回到了上面的处理办法。
那么问题来了,python有没有更好地办法呢?
答案是,有!
python的编码转换流程实际上是两段式转换:
source -> unicode -> dest
首先将字符串从原始编码转换成unicode。再将unicode转换成目标编码。
第一步我们一般采用decode()或者 unicode() 这两个函数完成。
第二步我们使用encode()函数完成。
在这里我们说的黑魔法就是在第一步实现。
decode和unicode函数都有一个叫做errors的可选参数。看看官方的描述:
errors may be given to set a different error
handling scheme. default is 'strict' meaning that encoding errors raise
a unicodedecodeerror. other possible values are 'ignore' and 'replace'
as well as any other name registered with codecs. register_error that is
able to handle unicodedecodeerrors.
这个参数通常有三种值:
strict 默认值。如果出现编码错误,则会抛出unicodedecodeerror。 ignore 跳过。 replace 用?替换。好了,看到最后一句话了吗?好戏上演了!
模块codec有一个函数叫做register_error。他的作用让用户可以注册自定义的errors处理方法。
用来处理unicodedecodeerror。
我们看看函数原型:
codecs.register_error(name, error_handler)
name: 错误处理的名称。用以填写在decode函数的error参数中。
error_handler: 处理函数。该函数接受一个异常参数。
返回一个tuple,该tuple有2个元素,第一个是纠错后的字符串,第二个是继续decode的起始位置
有了上面的基本概念。我们看下具体实现:
def cjk_error(e): if not isinstance(e, unicodedecodeerror): raise typeerror(don't know how to handle %r % exc) if exc.end + 1 > len(exc.object): raise typeerror('unknown codec ,the object too short!') ch1 = ord(exc.object[exc.start:exc.end]) newpos = exc.end + 1 ch2 = ord(exc.object[exc.start + 1:newpos]) sk = exc.object[exc.start:newpos] if 0x81<=ch1<=0xfe and (0x40<=ch2<=0x7e or 0x7e<=ch2<=0xfe): # gbk return (unicode(sk,'cp936'), newpos) if 0x81<=ch1<=0xfe and (0x40<=ch2<=0x7e or 0xa1 len(exc.object): raise typeerror('unknown codec ,the object too short!') ch1 = ord(exc.object[exc.start:exc.end]) newpos = exc.end + 1 ch2 = ord(exc.object[exc.start + 1:newpos]) sk = exc.object[exc.start:newpos] if src != 'gbk' and 0x81<=ch1<=0xfe and (0x40<=ch2<=0x7e or 0x7e<=ch2<=0xfe): # gbk return (unicode(sk,'cp936'), newpos) if src != 'big5' and 0x81<=ch1<=0xfe and (0x40<=ch2<=0x7e or 0xa1<=ch2<=0xfe): # big5 return (unicode(sk,'big5'), newpos) raise typeerror('unknown codec !')codecs.register_error(cjk_replace, cjk_replace)
当然,这个逻辑其实还是不够严谨的。虽然对于这种混合编码这种畸形活处理有点较真儿。
不过既然python提供这样的能力,大家可以一起来讨论下,我们怎么可以做的更好?
