python黑魔法之编码转换
我们在使用其他语言的库做编码转换时,对于无法理解的字符,通常的处理也只有两种(或三种):
但是在复杂的现实世界中,由于各种不靠谱,我们处理的文本总会出现那么些不和谐因素,比如混合编码。在这种情况下,又回到了上面的处理办法。 那么问题来了,python有没有更好地办法呢? 答案是,有! python的编码转换流程实际上是两段式转换: source -> unicode -> dest 首先将字符串从原始编码转换成unicode。再将unicode转换成目标编码。 第一步我们一般采用decode()或者 unicode() 这两个函数完成。 在这里我们说的黑魔法就是在第一步实现。 decode和unicode函数都有一个叫做errors的可选参数。看看官方的描述:
这个参数通常有三种值:
好了,看到最后一句话了吗?好戏上演了! 模块codec有一个函数叫做register_error。他的作用让用户可以注册自定义的errors处理方法。 我们看看函数原型: codecs.register_error(name,error_handler) name: 错误处理的名称。用以填写在decode函数的error参数中。 有了上面的基本概念。我们看下具体实现: 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<=ch2<=0xFE): # BIG5 return (unicode(sk,'big5'),newpos) raise TypeError('unknown codec !') codecs.register_error("cjk_replace",cjk_replace) 上面这个是我从网上copy的。开始我觉得很不错,但是后来发现是个很不经推敲的算法。 a = "你" # utf8编码:'xe4xbdxa0' c = unicode(a[:2],'gbk') # 正常返回 c = unicode(a,'gbk') # UnicodeDecodeError 。错误发生在第三个字节 所以针对这种情况,做了下改进: import codec def cjk_replace(e): if not isinstance(e,UnicodeDecodeError): raise TypeError("invalid exception type %s" e) src = e.encoding if src in ('gbk','gb18030','big5'): beg = e.start - 2 if beg >= 0: try: return unicode(e.object[beg:e.end],'utf8'),e.end + 1 except: pass 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 src != 'gbk' and 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0x7E<=ch2<=0xFE): # GBK return (unicode(sk,newpos) if src != 'big5' and 0x81<=ch1<=0xFE and (0x40<=ch2<=0x7E or 0xA1<=ch2<=0xFE): # BIG5 return (unicode(sk,newpos) raise TypeError('unknown codec !') codecs.register_error("cjk_replace",cjk_replace) 当然,这个逻辑其实还是不够严谨的。虽然对于这种混合编码这种畸形活处理有点较真儿。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |