如何处理python编码转换时的UnicodeDecodeError异常
python提供的unicode转换不像iconv或是mbstowcs之类的方便。
如果转换一段
unicode("1234中文",'ascii')
到utf8会直接出现UnicodeDecodeError的错误。如果在你能预知字串符的编码的时候,比如你用unicode('1234中文',
'gbk') 就不会出现错误,不过很多时候,会出现CJK混合的情况,如果要做到将一段CJK文件转换成unicode可能就行不通了。
好在python的codecs提供了register_error这个功能:
register_error( name, error_handler)
原
理很简单,不过要先看unicode是如何处理异常的,unicode这个函数是将一段string按输入的编码转换成目标的编码,如果出现了不与输入编
码相符的,会出现一个UnicodeDecodeError的异常,通常有三种处理方法:strict,replace,ignore,默认是
strict,就是直接raise UnicodeDecodeError.
通过register_error,我们也可以有自己的处理方法,如果遇到与输入的编码不符的时候,我们就自己识别,比如GBK的,比如BIG5,比如
JP的。
def cjk_replace(exc):
if not isinstance(exc, 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)
我
们的cjk_replace现在只能处理GBK与BIG5的,因为我对编码也不是特别了解,所以就大概知道GBK与BIG5的,JP的不知道是什么.在
cjk_replace这个函数里,我们对不认识的文字进行手工识别,如果认识的编码,就用正确的方法,并返回编码后的内容与新的pos,
比如"1234中文",在pos为4的时候,会调用我们的cjk_replace,我们会返回一个从gbk转换成utf8的’中‘字,并返回下个正确的位置‘文’的起始位置。当然了,处理‘文’的时候,还会再调用一次。T_T
看看是如何使用的
filedata = open('test.txt','r).read() #gbk and big5 file
data = unicode(filedata,'ascii','cjk_replace').encode('utf8')