2.12 審查清理文本字符串

2018-02-24 15:26 更新

問題

一些無聊的幼稚黑客在你的網(wǎng)站頁面表單中輸入文本”pyt???”,然后你想將這些字符清理掉。

解決方案

文本清理問題會涉及到包括文本解析與數(shù)據(jù)處理等一系列問題。在非常簡單的情形下,你可能會選擇使用字符串函數(shù)(比如 str.upper()str.lower() )將文本轉(zhuǎn)為標(biāo)準(zhǔn)格式。使用 str.replace() 或者 re.sub() 的簡單替換操作能刪除或者改變指定的字符序列。你同樣還可以使用2.9小節(jié)的 unicodedata.normalize() 函數(shù)將unicode文本標(biāo)準(zhǔn)化。

然后,有時(shí)候你可能還想在清理操作上更進(jìn)一步。比如,你可能想消除整個(gè)區(qū)間上的字符或者去除變音符。為了這樣做,你可以使用經(jīng)常會被忽視的 str.translate() 方法。為了演示,假設(shè)你現(xiàn)在有下面這個(gè)凌亂的字符串:

>>> s = 'pyt???\fis\tawesome\r\n'
>>> s
'pyt???\x0cis\tawesome\r\n'
>>>

第一步是清理空白字符。為了這樣做,先創(chuàng)建一個(gè)小的轉(zhuǎn)換表格然后使用 translate() 方法:

>>> remap = {
...     ord('\t') : ' ',
...     ord('\f') : ' ',
...     ord('\r') : None # Deleted
... }
>>> a = s.translate(remap)
>>> a
'pyt??? is awesome\n'
>>>

正如你看的那樣,空白字符t和f已經(jīng)被重新映射到一個(gè)空格。回車字符r直接被刪除。

你可以以這個(gè)表格為基礎(chǔ)進(jìn)一步構(gòu)建更大的表格。比如,讓我們刪除所有的和音符:

>>> import unicodedata
>>> import sys
>>> cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode)
...                         if unicodedata.combining(chr(c)))
...
>>> b = unicodedata.normalize('NFD', a)
>>> b
'pyt??? is awesome\n'
>>> b.translate(cmb_chrs)
'python is awesome\n'
>>>

上面例子中,通過使用 dict.fromkeys() 方法構(gòu)造一個(gè)字典,每個(gè)Unicode和音符作為鍵,對于的值全部為None。

然后使用 unicodedata.normalize() 將原始輸入標(biāo)準(zhǔn)化為分解形式字符。然后再調(diào)用 translate 函數(shù)刪除所有重音符。同樣的技術(shù)也可以被用來刪除其他類型的字符(比如控制字符等)。

作為另一個(gè)例子,這里構(gòu)造一個(gè)將所有Unicode數(shù)字字符映射到對應(yīng)的ASCII字符上的表格:

>>> digitmap = { c: ord('0') + unicodedata.digit(chr(c))
...         for c in range(sys.maxunicode)
...         if unicodedata.category(chr(c)) == 'Nd' }
...
>>> len(digitmap)
460
>>> # Arabic digits
>>> x = '\u0661\u0662\u0663'
>>> x.translate(digitmap)
'123'
>>>

另一種清理文本的技術(shù)設(shè)計(jì)到I/O解碼與編碼函數(shù)。這里的思路是先對文本做一些初步的清理,然后再結(jié)合 encode() 或者 decode() 操作來清除或修改它。比如:

>>> a
'pyt??? is awesome\n'
>>> b = unicodedata.normalize('NFD', a)
>>> b.encode('ascii', 'ignore').decode('ascii')
'python is awesome\n'
>>>

這里的標(biāo)準(zhǔn)化操作將原來的文本分解為單獨(dú)的和音符。接下來的ASCII編碼/解碼只是簡單的一下子丟棄掉那些字符。當(dāng)然,這種方法僅僅只在最后的目標(biāo)就是獲取到文本對應(yīng)ACSII表示的時(shí)候生效。

討論

文本字符清理一個(gè)最主要的問題應(yīng)該是運(yùn)行的性能。一般來講,代碼越簡單運(yùn)行越快。對于簡單的替換操作,str.replace() 方法通常是最快的,甚至在你需要多次調(diào)用的時(shí)候。比如,為了清理空白字符,你可以這樣做:

def clean_spaces(s):
    s = s.replace('\r', '')
    s = s.replace('\t', ' ')
    s = s.replace('\f', ' ')
    return s

如果你去測試的話,你就會發(fā)現(xiàn)這種方式會比使用 translate() 或者正則表達(dá)式要快很多。

另一方面,如果你需要執(zhí)行任何復(fù)雜字符對字符的重新映射或者刪除操作的話,tanslate() 方法會非常的快。

從大的方面來講,對于你的應(yīng)用程序來說性能是你不得不去自己研究的東西。不幸的是,我們不可能給你建議一個(gè)特定的技術(shù),使它能夠適應(yīng)所有的情況。因此實(shí)際情況中需要你自己去嘗試不同的方法并評估它。

盡管這一節(jié)集中討論的是文本,但是類似的技術(shù)也可以適用于字節(jié),包括簡單的替換,轉(zhuǎn)換和正則表達(dá)式。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號