全文共8032字,預計學習時長16分鐘
處理文本數據的一個主要任務就是創建許多以文本為基礎的特性。
人們可能想要在文本中找出特定格式的內容,比如找出存在於文本中的電子郵件,或者大型文本中的電話號碼。
雖然想要實現上述功能聽起來很繁瑣,但是如果使用Python正則表達式模塊,就可以使這一操作更加簡單。
假設要在一篇特定的文章中找出標點符號的數量。以狄更斯的作品文本為例。
你通常會怎麼做?
最簡單的方法如下:
target = [';','.',',','–']
string = "It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way – in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only."
num _ points = 0
num_puncts = 0
for punct in target:
if punct in string:
num_puncts+=string.count(punct)print(num_puncts)
-
19
如果沒有可支配的re模塊,那就要用到上面的代碼。但如果有re模塊,則只需兩行代碼:
import re
pattern = r"[;.,–]"
print(len(re.findall(pattern,string)))
-
19
本文討論的是最常用的正則表達式模式,以及一些經常使用的正則表達式函數。
什麼是正則表達式?
簡而言之,正則表達式(regex)用於探索給定字符串中的固定模式。
我們想找到的模式可以是任何東西。
可以創建類似於查找電子郵件或手機號碼的模式。還可以創建查找以a開頭、以z結尾的字符串的模式。
在上面的例子中:
import re
pattern = r'[,;.,–]'
print(len(re.findall(pattern,string)))
我們想找出的模式是 r』[,;.,–]』。這個模式可找出想要的4個字符中的任何一個。regex101是一個用於測試模式的工具。將模式應用到目標字符串時,呈現出以下界面。
如圖所示,可以在目標字符串中根據需要找到,;.,–。
每當需要測試正則表達式時,都會用到上面的工具。這比一次又一次運行python要快得多,調試也容易得多。
現在我們已經可以在目標字符串中找到這些模式,那麼如何真正創建這些模式呢?
創建模式
使用正則表達式時,首先需要學習的是如何創建模式。
接下來將對一些最常用的模式進行逐一介紹。
可以想到最簡單的模式是一個簡單的字符串。
pattern = r'times'
string = "It was the best of times, it was the worst of times."
print(len(re.findall(pattern,string)))
但這並不是很有用。為了幫助創建複雜的模式,正則表達式提供了特殊的字符/操作符。下面來逐個看看這些操作符。請等待gif加載。
1.[]操作符
這在第一個例子中使用過,可用於找到符合這些方括號中條件的一個字符。
[abc]-將查找文本中出現的所有a、b或c
[a-z]-將查找文本中出現的所有從a到z的字母
[a-z0–9A-Z]-將查找文本中出現的所有從A到Z的大寫字母、從a到z的小寫字母和從0到9的數字。
可以很容易地在Python中運行下列代碼:
pattern = r'[a-zA-Z]'
string = "It was the best of times, it was the worst of times."
print(len(re.findall(pattern,string)))
除了.findall,正則表達式還有很多其他功能,稍後會涉及到。
2.點算符
點運算符(.) 用於匹配除換行符以外的任何字符。
運算符最大的優點是,它們可以結合使用。
例如,想在字符串中找出以小d或大寫D開頭,以字母e結尾,包含6個字母的子字符串。
3.一些元序列
在使用正則表達式時,一些模式會經常被用到。因此正則表達式為這些模式創建了一些快捷方式。最常用的快捷方式如下:
\w,匹配任何字母、數字或下劃線。相當於[a-zA-Z0–9_]
\W,匹配除字母、數字或下劃線以外的任何內容。
\d,匹配任何十進位數字。相當於[0–9]。
\D,匹配除十進位數字以外的任何數字。
4.加號和星形運算符
點算符只是用於獲取任何字符的單個實例。如果想找出更多實例要怎麼做呢?
加號+用於表示最左邊字符的一個或多個實例。
星號*用於表示最左邊字符的0個或多個實例。
例如,如果想找出所有以d開頭,以e結尾的子字符串,d和e之間可以沒有也可以有多個字符。我們可以用:d\w*e
如果想找出所有以d開頭,以e結尾的子字符串,在d和e之間至少有一個字符,我們可以用:d\w+e
還可以使用更為通用的方法:用{}
\w{n} - 重複\w 正好n次。
\w{n,} - 重複\w至少n次,或者更多次。
\w{n1, n2} - 重複 \w 至少n1次,但不超過n2次。
5.^插入符號和$美元符號。
^插入符號匹配字符串的開始,而$美元符號則匹配字符串的結尾。
6.單詞邊界
這是一個重要的概念。
有沒有注意到,在上面的例子中,總是匹配子字符串,而不是匹配單詞?
如果想找出所有以d開頭的單詞呢?
可以使用d\w*模式嗎?下面用網絡工具來試一試吧。
正則表達式函數
目前為止,只使用了 re包中的findall 函數,其實還有很多其他函數。下面來逐個介紹。
1. findall
上面已經使用了 findall。這是我最常使用的一個。下面來正式認識一下這個函數吧。
輸入:模式和測試字符串
輸出:字符串列表。
#USAGE:
pattern = r'[iI]t'
string = "It was the best of times, it was the worst of times."
matches = re.findall(pattern,string)
for match in matches:
print(match)
It
it
2.搜索
輸入:模式和測試字符串
輸出:首次匹配的位置對象。
#USAGE:
pattern = r'[iI]t'
string = "It was the best of times, it was the worst of times."
location = re.search(pattern,string)
print(location)
<_sre.SRE_Match object; span=(0, 2), match='It'>
可以使用下面編程獲取該位置對象的數據:
print(location.group())
'It'
3.替換
這個功能也很重要。當使用自然語言處理程序時,有時需要用X替換整數,或者可能需要編輯一些文件。任何文本編輯器中的查找和替換都可以做到。
輸入:搜索模式、替換模式和目標字符串
輸出:替換字符串
string = "It was the best of times, it was the worst of times."
string = re.sub(r'times', r'life', string)
print(string)
It was the best of life, it was the worst of life.
案例研究
正則表達式在許多需要驗證的情況下都會用到。我們可能會在網站上看到類似這樣的提示:「這不是有效的電子郵件地址」。雖然可以使用多個if和else條件來編寫這樣的提示,但正則表達式可能更具優勢。
1.PAN編號
在美國,SSN(社會安全號碼)是用於稅務識別的號碼,而在印度,稅務識別用的則是 PAN號碼。PAN的基本驗證標準是:上面所有的字母都必須大寫,字符的順序如下:
<char><char><char><char><char><digit><digit><digit><digit><char>
那麼問題是:
「ABcDE1234L」是有效的PAN號碼嗎?
如果沒有正則表達式,該如何回答這個問題呢?可能會編寫一個for循環,並進行遍歷搜索。但如果用正則表達式,那就像下面這樣簡單:
match=re.search(r』[A-Z]{5}[0–9]{4}[A-Z]』,'ABcDE1234L')
if match:
print(True)
else:
print(False)
False
2.查找域名
有時我們必須從一個龐大的文本文檔中找出電話號碼、電子郵件地址或域名等。
例如,假設有以下文本:
<div style="list-style-type: decimal;">
<ol>
<li id="cite_note-1"><span><b>^ ["Train (noun)"](http://www.askoxford.com/concise_oed/train?view=uk). <i>(definition – Compact OED)</i>. Oxford University Press<span>. Retrieved 2008-03-18</span>.</span><span title="ctx_ver=Z39.88-2004&rfr_id=info%3Asid%2Fen.wikipedia.org%3ATrain&rft.atitle=Train+%28noun%29&rft.genre=article&rft_id=http%3A%2F%2Fwww.askoxford.com%2Fconcise_oed%2Ftrain%3Fview%3Duk&rft.jtitle=%28definition+%E2%80%93+Compact+OED%29&rft.pub=Oxford+University+Press&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal"><span style="display:none;"> </span></span></span></li>
<li id="cite_note-2"><span><b>^</b></span> <span><span>Atchison, Topeka and Santa Fe Railway (1948). <i>Rules: Operating Department</i>. p. 7.</span><span title="ctx_ver=Z39.88-2004&rfr_id=info%3Asid%2Fen.wikipedia.org%3ATrain&rft.au=Atchison%2C+Topeka+and+Santa+Fe+Railway&rft.aulast=Atchison%2C+Topeka+and+Santa+Fe+Railway&rft.btitle=Rules%3A+Operating+Department&rft.date=1948&rft.genre=book&rft.pages=7&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook"><span style="display:none;"> </span></span></span></li>
<li id="cite_note-3"><span><b>^ [Hydrogen trains](http://www.hydrogencarsnow.com/blog2/index.php/hydrogen-vehicles/i-hear-the-hydrogen-train-a-comin-its-rolling-round-the-bend/)</span></li>
<li id="cite_note-4"><span><b>^ [Vehicle Projects Inc. Fuel cell locomotive](http://www.bnsf.com/media/news/articles/2008/01/2008-01-09a.html)</span></li>
<li id="cite_note-5"><span><b>^</b></span> <span><span>Central Japan Railway (2006). <i>Central Japan Railway Data Book 2006</i>. p. 16.</span><span title="ctx_ver=Z39.88-2004&rfr_id=info%3Asid%2Fen.wikipedia.org%3ATrain&rft.au=Central+Japan+Railway&rft.aulast=Central+Japan+Railway&rft.btitle=Central+Japan+Railway+Data+Book+2006&rft.date=2006&rft.genre=book&rft.pages=16&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Abook"><span style="display:none;"> </span></span></span></li>
<li id="cite_note-6"><span><b>^ ["Overview Of the existing Mumbai Suburban Railway"](http://web.archive.org/web/20080620033027/http://www.mrvc.indianrail.gov.in/overview.htm). _Official webpage of Mumbai Railway Vikas Corporation_. Archived from [the original](http://www.mrvc.indianrail.gov.in/overview.htm) on 2008-06-20<span>. Retrieved 2008-12-11</span>.</span><span title="ctx_ver=Z39.88-2004&rfr_id=info%3Asid%2Fen.wikipedia.org%3ATrain&rft.atitle=Overview+Of+the+existing+Mumbai+Suburban+Railway&rft.genre=article&rft_id=http%3A%2F%2Fwww.mrvc.indianrail.gov.in%2Foverview.htm&rft.jtitle=Official+webpage+of+Mumbai+Railway+Vikas+Corporation&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Ajournal"><span style="display:none;"> </span></span></span></li>
</ol>
</div>
需要從上面文本中找出這裡所有的域名—— askoxford.com;bnsf.com;hydrogencarsnow.com;mrvc.indianrail.gov.in;web.archive.org
該怎麼做?
match=re.findall(r'http(s:|:)\/\/(www.|ww2.|)([0-9a-z.A-Z-]*\.\w{2,3})',string)
for elem in match:
print(elem)
---
(':', 'www.', 'askoxford.com')
(':', 'www.', 'hydrogencarsnow.com')
(':', 'www.', 'bnsf.com')
(':', '', 'web.archive.org')
(':', 'www.', 'mrvc.indianrail.gov.in')
(':', 'www.', 'mrvc.indianrail.gov.in')
這裡用到了or運算符,match返回元組,保留()裡的模式部分。
3.查找電子郵件地址:
下面的正則表達式用於在長文本中查找電子郵件地址。
match=re.findall(r'([\w0-9-._]+@[\w0-9-.]+[\w0-9]{2,3})',string)
這些都是高級示例,提供的信息已經足夠幫你理解這些示例了。
結論
雖然正則表達式看起來令人生畏,但它在數據操作、創建特性和尋找模式方面具有高度的靈活性。
留言 點讚 關注
我們一起分享AI學習與發展的乾貨
編譯組:殷睿宣、李林虹
相關連結:
https://towardsdatascience.com/the-ultimate-guide-to-using-the-python-regex-module-69aad9e9ba56
如需轉載,請後臺留言,遵守轉載規範