国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

python黑魔法之編碼轉(zhuǎn)換

2020-01-04 17:48:29
字體:
供稿:網(wǎng)友
這篇文章主要介紹了python黑魔法之編碼轉(zhuǎn)換,分析了python編碼轉(zhuǎn)換的方法,感興趣的小伙伴們可以參考一下
 

我們在使用其他語言的庫做編碼轉(zhuǎn)換時(shí),對于無法理解的字符,通常的處理也只有兩種(或三種):

  • 拋異常
  • 替換成替代字符
  • 跳過

但是在復(fù)雜的現(xiàn)實(shí)世界中,由于各種不靠譜,我們處理的文本總會出現(xiàn)那么些不和諧因素,比如混合編碼。在這種情況下,又回到了上面的處理辦法。

那么問題來了,python有沒有更好地辦法呢?

答案是,有!

python的編碼轉(zhuǎn)換流程實(shí)際上是兩段式轉(zhuǎn)換:

source -> unicode -> dest

首先將字符串從原始編碼轉(zhuǎn)換成unicode。再將unicode轉(zhuǎn)換成目標(biāo)編碼。

第一步我們一般采用decode()或者 unicode() 這兩個(gè)函數(shù)完成。
第二步我們使用encode()函數(shù)完成。

在這里我們說的黑魔法就是在第一步實(shí)現(xiàn)。

decode和unicode函數(shù)都有一個(gè)叫做errors的可選參數(shù)??纯垂俜降拿枋觯?/p>

  • 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.

這個(gè)參數(shù)通常有三種值:

  • strict 默認(rèn)值。如果出現(xiàn)編碼錯誤,則會拋出UnicodeDecodeError。
  • ignore 跳過。
  • replace 用?替換。

好了,看到最后一句話了嗎?好戲上演了!

模塊codec有一個(gè)函數(shù)叫做register_error。他的作用讓用戶可以注冊自定義的errors處理方法。
用來處理UnicodeDecodeError。

我們看看函數(shù)原型:

codecs.register_error(name, error_handler)

name: 錯誤處理的名稱。用以填寫在decode函數(shù)的error參數(shù)中。
error_handler: 處理函數(shù)。該函數(shù)接受一個(gè)異常參數(shù)。
返回一個(gè)tuple,該tuple有2個(gè)元素,第一個(gè)是糾錯后的字符串,第二個(gè)是繼續(xù)decode的起始位置

有了上面的基本概念。我們看下具體實(shí)現(xiàn):

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) 

上面這個(gè)是我從網(wǎng)上copy的。開始我覺得很不錯,但是后來發(fā)現(xiàn)是個(gè)很不經(jīng)推敲的算法。
比如utf8和gbk在前兩個(gè)字節(jié)就有交集的部分。當(dāng)一個(gè)utf8的字符串以gbk編碼decode的時(shí)候,出現(xiàn)錯誤是從第三個(gè)字節(jié)開始(前兩個(gè)字節(jié)也能夠在gbk編碼范圍中對應(yīng)到一個(gè)漢字)。
如:

a = "你"              # utf8編碼:'/xe4/xbd/xa0'c = unicode(a[:2],'gbk')  # 正常返回c = unicode(a, 'gbk')    # UnicodeDecodeError 。錯誤發(fā)生在第三個(gè)字節(jié)

所以針對這種情況,做了下改進(jìn):

import codecdef 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)

當(dāng)然,這個(gè)邏輯其實(shí)還是不夠嚴(yán)謹(jǐn)?shù)?。雖然對于這種混合編碼這種畸形活處理有點(diǎn)較真兒。
不過既然python提供這樣的能力,大家可以一起來討論下,我們怎么可以做的更好?


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 上蔡县| 巴里| 聂荣县| 元谋县| 唐海县| 巴南区| 镇远县| 宁德市| 拉萨市| 顺昌县| 自治县| 平顺县| 涞源县| 玛多县| 汉阴县| 广河县| 子洲县| 汤阴县| 东丽区| 中方县| 双辽市| 枣阳市| 石家庄市| 义乌市| 长顺县| 应用必备| 班戈县| 浪卡子县| 鄯善县| 博野县| 桃园市| 临汾市| 沁源县| 贞丰县| 云龙县| 西宁市| 高雄市| 阿拉尔市| 孟州市| 肇州县| 吉安市|