上一篇文章: Python實用技法第30篇:從字符串中去掉不須要的字符
下一篇文章: Python實用技法第32篇:對齊文本字符串
某些無聊的腳本小子在Web頁面表單中填入了「pýtĥöñ」這樣的文本,咱們想以某種方式將其清理掉。python
文本過濾和清理所涵蓋的範圍很是普遍,涉及文本解析和數據處理方面的問題。在很是簡單的層次上,咱們可能會用基本的字符串函數(例如str.upper()和str.lower())將文本轉換爲標準形式。簡單的替換操做可經過str.replace()或re.sub()來完成,它們把重點放在移除或修改特定的字符序列上。也能夠利用unicodedata.normalize()來規範化文本。git
然而咱們可能想更進一步。比方說也許想清除整個範圍內的字符,或者去掉音符標誌。要完成這些任務,可使用常被忽視的str.translate()方法。爲了說明其用法,假設有以下這段混亂的字符串:正則表達式
>>> s = 'pytĥon\fis\tawesome\r\n' >>> s 'pytĥon\x0cis\tawesome\r\n' >>>
第一步是清理空格。要作到這步,先創建一個小型的轉換表,而後使用translate()方法:segmentfault
>>> remap = { ... ord('\t') : ' ', ... ord('\f') : ' ', ... ord('\r') : None # Deleted ... } >>> a = s.translate(remap) >>> a 'pytĥon is awesome\n'
能夠看到,相似t和f這樣的空格符已經被從新映射成一個單獨的空格。回車符r已經徹底被刪除掉了。函數
能夠利用這種從新映射的思想進一步構建出更加龐大的轉換表。例如,咱們把全部的Unicode組合字符都去掉:性能
>>> 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ĥon is awesome\n' >>> b.translate(cmb_chrs) 'python is awesome\n' >>>
在這個例子中,咱們使用dict.fromkeys()方法構建了一個將每一個Unicode組合字符都映射爲None的字典。編碼
原始輸入會經過unicodedata.normalize()方法轉換爲分離形式,而後再經過translate()方法刪除全部的重音符號。咱們也能夠利用類似的技術來去掉其餘類型的字符(例如控制字符)。spa
下面來看另外一個例子。這裏有一張轉換表將全部的Unicode十進制數字字符映射爲它們對應的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' >>>
另外一種用來清理文本的技術涉及I/O解碼和編碼函數。大體思路是首先對文本作初步的清理,而後經過結合encode()和decode()操做來修改或清理文本。示例以下:code
>>> a 'pytĥon is awesome\n' >>> b = unicodedata.normalize('NFD', a) >>> b.encode('ascii', 'ignore').decode('ascii') 'python is awesome\n' >>>
這裏的normalize()方法先對原始文本作分解操做。後續的ASCII編碼/解碼只是簡單地一次性丟棄全部不須要的字符。很顯然,這種方法只有當咱們的最終目標就是ASCII形式的文本時纔有用。
文本過濾和清理的一個主要問題就是運行時的性能。通常來講操做越簡單,運行得就越快。對於簡單的替換操做,用str.replace()一般是最快的方式——即便必須屢次調用它也是如此。比方說若是要清理掉空格符,能夠編寫以下的代碼:
def clean_spaces(s): s = s.replace('\r', '') s = s.replace('\t', ' ') s = s.replace('\f', ' ') return s
若是試着調用它,就會發現這比使用translate()或者正則表達式的方法要快得多。
另外一方面,若是須要作任何高級的操做,好比字符到字符的重映射或刪除,那麼translate()方法仍是很是快的。
從總體來看,咱們應該在具體的應用中去進一步揣摩性能方面的問題。不幸的是,想在技術上給出一條「放之四海而皆準」的建議是不可能的,因此應該嘗試多種不一樣的方法,而後作性能統計分析。
儘管本節的內容主要關注的是文本,但相似的技術也一樣適用於字節對象(byte),這包括簡單的替換、翻譯和正則表達式。
上一篇文章: Python實用技法第30篇:從字符串中去掉不須要的字符
下一篇文章: Python實用技法第32篇:對齊文本字符串