激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - python黑魔法之編碼轉換

python黑魔法之編碼轉換

2020-08-10 10:12icedoom Python

這篇文章主要介紹了python黑魔法之編碼轉換,分析了python編碼轉換的方法,感興趣的小伙伴們可以參考一下

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

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

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

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

答案是,有!

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

?
1
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 用?替換。

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

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

我們看看函數原型:

?
1
codecs.register_error(name, error_handler)

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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編碼范圍中對應到一個漢字)。
如:

?
1
2
3
a = "你"              # utf8編碼:'\xe4\xbd\xa0'
c = unicode(a[:2],'gbk'# 正常返回
c = unicode(a, 'gbk')    # UnicodeDecodeError 。錯誤發生在第三個字節

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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提供這樣的能力,大家可以一起來討論下,我們怎么可以做的更好?

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 综合精品 | av手机在线免费播放 | 色日本视频 | 中文字幕在线看第二 | 亚洲成人免费影视 | 日韩99| 欧美成人性生活 | 国产一级伦理片 | 久久久久久久久成人 | 国产一区视频在线观看免费 | 成年性羞羞视频免费观看 | 成人三级黄色片 | 激情小说区 | 久啪视频 | 久久成人免费网 | 成人区一区二区 | 网站激情| 久久久久久久久国产 | 日本一区二区视频在线观看 | 羞羞答答视频 | 午夜天堂在线 | 黄色免费小网站 | 91,视频免费看 | 视频一区二区三区在线播放 | xnxx 美女19 | 免费国产视频大全入口 | 免费视频a | 一级免费毛片 | 斗破苍穹在线免费 | 一区二区精品视频在线观看 | 日本aaaa片毛片免费观看视频 | 国产日韩欧美一区 | 午夜影院在线免费观看 | 九九热免费观看 | 一级美女大片 | 成人精品一区二区 | 成人三级黄色片 | 一级免费特黄视频 | 欧美区在线 | 日本在线高清 | 成年人黄视频 |