這篇文章主要介紹了python黑魔法之編碼轉換,分析了python編碼轉換的方法,感興趣的小伙伴們可以參考一下
我們在使用其他語言的函式庫做編碼轉換時,對於無法理解的字符,通常的處理也只有兩種(或三種):
拋異常
#取代為替代字元
跳過
但是在複雜的現實世界中,由於各種不靠譜,我們處理的文本總會出現那麼些不和諧因素,比如混合編碼。在這種情況下,又回到了上面的處理辦法。
那麼問題來了,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 用?來替換。
用來處理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<=ch2<=0xFE): # BIG5 return (unicode(sk,'big5'), newpos) raise TypeError('unknown codec !') codecs.register_error("cjk_replace", cjk_replace)上面這個是我從網路上
copy的。開始我覺得很不錯,但是後來發現是個很不經推敲的演算法。 例如utf8和gbk在前兩個位元組就有交集的部分。當一個utf8的字串以gbk編碼decode的時候,出現錯誤是從第三個位元組開始(前兩個位元組也能夠在gbk編碼範圍中對應到一個漢字)。
如:
a = "你" # utf8编码:'\xe4\xbd\xa0' 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,'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提供這樣的能力,大家可以一起來討論下,我們怎麼可以做的更好?
以上是python黑魔法之編碼轉換方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!