python 黑魔法之 編碼轉換

2021-09-23 23:21:22 字數 3819 閱讀 1855

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

但是在複雜的現實世界中,由於各種不靠譜,我們處理的文字總會出現那麼些不和諧因素,比如混合編碼。在這種情況下,又回到了上面的處理辦法。

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

答案是,有!

python的編碼轉換流程實際上是兩段式轉換:

source ->

unicode -> dest

首先將字串從原始編碼轉換成unicode。再將unicode轉換成目標編碼。

第一步我們一般採用decode()或者unicode()這兩個函式完成。

第二步我們使用encode()函式完成。

在這裡我們說的黑魔法就是在第一步實現。

decodeunicode函式都有乙個叫做errors的可選引數。看看官方的描述:

errorsmay 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

.

這個引數通常有三種值:

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

模組codec有乙個函式叫做register_error。他的作用讓使用者可以註冊自定義的errors處理方法。

用來處理unicodedecodeerror

我們看看函式原型:

name: 錯誤處理的名稱。用以填寫在decode函式的error引數中。

error_handler: 處理函式。該函式接受乙個異常引數。

返回乙個tuple,該tuple有2個元素,第乙個是糾錯後的字串,第二個是繼續decode的起始位置

有了上面的基本概念。我們看下具體實現:

def

cjk_error

(e):

ifnot 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]

if0x81

<=ch1<=0xfe

and (0x40

<=ch2<=0x7e

or0x7e

<=ch2<=0xfe): # gbk

return (unicode(sk,'cp936'), newpos)

if0x81

<=ch1<=0xfe

and (0x40

<=ch2<=0x7e

or0xa1

<=ch2<=0xfe): # big5

return (unicode(sk,'big5'), newpos)

raise typeerror('unknown codec !')

codecs.register_error("cjk_replace", cjk_replace)

上面這個是我從網上copy的。開始我覺得很不錯,但是後來發現是個很不經推敲的演算法。

比如utf8gbk在前兩個位元組就有交集的部分。當乙個utf8的字串以gbk編碼decode的時候,出現錯誤是從第三個位元組開始(前兩個位元組也能夠在gbk編碼範圍中對應到乙個漢字)。

如:

a = "你"                            # utf8編碼:'\xe4\xbd\xa0'

c = unicode(a[:2],'gbk') # 正常返回

c = unicode(a, 'gbk') # unicodedecodeerror 。錯誤發生在第三個位元組

所以針對這種情況,做了下改進:

import codec

defcjk_replace

(e):

ifnot 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'

and0x81

<=ch1<=0xfe

and (0x40

<=ch2<=0x7e

or0x7e

<=ch2<=0xfe): # gbk

return (unicode(sk,'cp936'), newpos)

if src != 'big5'

and0x81

<=ch1<=0xfe

and (0x40

<=ch2<=0x7e

or0xa1

<=ch2<=0xfe): # big5

return (unicode(sk,'big5'), newpos)

raise typeerror('unknown codec !')

codecs.register_error("cjk_replace", cjk_replace)

當然,這個邏輯其實還是不夠嚴謹的。雖然對於這種混合編碼這種畸形活處理有點較真兒。

不過既然python提供這樣的能力,大家可以一起來討論下,我們怎麼可以做的更好,娛樂下。

python 黑魔法之編碼轉換

我們在使用其他語言的庫做編碼轉換時,對於無法理解的字元,通常的處理也只有兩種 或三種 但是在複雜的現實世界中,由於各種不靠譜,我們處理的文字總會出現那麼些不和諧因素,比如混合編碼。在這種情況下,又回到了上面的處理辦法。那麼問題來了,python有沒有更好地辦法呢?答案是,有!python的編碼轉換流...

Python黑魔法 元類

python黑魔法 元類 術語 元程式設計 指的是程式具有編寫或操縱其自身作為它們資料的潛力。python支援稱為元類的類的元程式設計。元類是乙個深奧的物件導向程式設計 oop 概念,隱藏在幾乎所有的python 之後。無論你是否意識到它的存在,你都一直在使用它們。大多數情況下,你並不需要了解它。而...

css整理之 技巧 黑魔法

css 看起來比較簡單,但是要想做的好也不是那麼容易,我們在平時開發中,主要用css 來美化我們的html結構,所有我覺得css 還是挺重要的,這裡記錄整理一些關於css 的技巧以及容易忘記的知識點。在遇到css問題時,我一般從以下思路來思考 從元素本身的屬性出發,組合各種可能 嘗試如果把相關屬性設...