練習(xí) 31:正則表達(dá)式
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
自豪地采用谷歌翻譯
正則表達(dá)式(RegEx)是一種簡(jiǎn)潔的方式,用于確定字符序列應(yīng)如何在字符串中匹配。通常大家都認(rèn)為它們是“可怕”的,但是,正如你所知道的,任何包含在恐懼中的東西通常都不是這樣。正則表達(dá)式的事實(shí)是,它們是大約八個(gè)符號(hào)的集合,告訴計(jì)算機(jī)如何匹配模式串。簡(jiǎn)單來(lái)說(shuō),他們很容易理解。人們遇到困難的地方是,嘗試使用難以置信的復(fù)雜的正則表達(dá)式,其中解析器實(shí)際上會(huì)更好。一旦你明白了這八個(gè)符號(hào)和正則表達(dá)式的限制,你就會(huì)看到它們根本不可怕。
我打算讓你記憶更多東西,使你的的大腦為討論做好準(zhǔn)備。
^
錨定字符串開(kāi)頭。只有字符串剛好位于開(kāi)頭,它才會(huì)匹配。
$
錨定字符串末尾。只有字符串到達(dá)了末尾,它才會(huì)匹配。
.
任何單個(gè)字符。接受任何單個(gè)字符的輸入。
?
正則表達(dá)式的之前的部分是可選的,所以
A?
的意思是可選的字符A
。
*
之前的部分是零個(gè)或多個(gè)(任意個(gè))。選取正則表達(dá)式的之前的部分,重復(fù)接受或者跳過(guò)它。
A*
會(huì)接受"AAAAAAA"
或者"BQEFT"
,因?yàn)樗锩嬗辛銈€(gè)A
。
+
之前的部分是一個(gè)或多個(gè)(至少一個(gè))。和
*
類似,但是只接受一個(gè)或多個(gè)這種字符。A+
會(huì)匹配"AAAAAAA"
,但不是"BQEFT"
。
[X-Y]
X
到Y
的字符范圍,接受任何范圍中列出的字符串。[A-Z]
表示所有大寫英文字母。許多常見(jiàn)字符范圍擁有\
快捷方式,你可以使用它來(lái)代替。
()
捕獲這個(gè)正則表達(dá)式的部分,便于稍后使用。許多正則表達(dá)式庫(kù)將其用于替換、提取或修改文本。捕獲會(huì)選取正則表達(dá)式的
()
中的部分,并保存它便于以后使用。之后許多庫(kù)可以讓你引用這些捕獲。如果你使用([A-Z]+)
,它會(huì)捕獲一個(gè)或多個(gè)大寫英文單詞。
Python 的re
庫(kù)列出了一些更多的符號(hào),但大多都是這八個(gè)的一些修飾符,或者不在正則表達(dá)式庫(kù)中經(jīng)常發(fā)現(xiàn)的額外功能。你將快速記住這八個(gè)來(lái)起步,重點(diǎn)是粗體的部分(錨定末尾,之前部分可選),以便你可以快速回憶它們并解釋他們的作用。
記住這些符號(hào)后,請(qǐng)查看以下正則表達(dá)式并將其翻譯成中文,并使用 Python re
庫(kù)來(lái)嘗試列出的字符串,或你可以想到的任何其他字符串。
".*BC?$"
helloBC
,helloB
,helloA
,helloBCX
"[A-Za-z][0-9]+"
A1232344
,abc1234
,12345
,b493034
"^[0-9]?a*b?.$"
0aaaax
,aaab9
,9x
,88aabb
,9zzzz
"A+B+C+[xyz]*"
AAAABBCCCCCCxyxyz
,ABBBBCCCxxxx
,ABABABxxxx
一旦你翻譯了它們,使用Python re
模塊,嘗試在 Shell 中嘗試它們,如下:
>>> import re
>>> m = re.match(r".*BC?$", "helloB").span()
>>> re.match(r".*BC?$", "helloB").span()
(0, 6)
>>> re.match(r"[A-Za-z][0-9]+", "A1232344").span()
(0, 8)
>>> re.match(r"[A-Za-z][0-9]+", "abc1234").span()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'span'
>>> re.match(r"[A-Za-z][0-9]+", "1234").span()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'span'
>>> re.match(r"[A-Za-z][0-9]+", "b493034").span()
(0, 7)
>>>
對(duì)于任何不匹配,你會(huì)得到AttributeError: 'NoneType'
,因?yàn)楫?dāng)你的正則表達(dá)式不匹配時(shí),re.match
函數(shù)返回None
。
挑戰(zhàn)練習(xí)
挑戰(zhàn)是嘗試使用你的 FSM 模塊來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的正則表達(dá)式,至少執(zhí)行三個(gè)操作。這將是一個(gè)困難的挑戰(zhàn),但使用 Python re
庫(kù)來(lái)幫助你規(guī)劃和測(cè)試此正則表達(dá)式的實(shí)現(xiàn)。然后,一旦你知道如何實(shí)現(xiàn)它,永遠(yuǎn)不要這樣做了。人生苦短,不要做計(jì)算機(jī)已經(jīng)擅長(zhǎng)的事情。
研究性學(xué)習(xí)
- 擴(kuò)展你的記憶,來(lái)包括 Python
re
庫(kù)文檔中的所有可能的符號(hào)。 - 如果你想要匹配一個(gè)
*
字符,那么你可以用\*
來(lái)轉(zhuǎn)義它。大多數(shù)其他符號(hào)也有類似的東西。 - 確保你知道如何使用
re.ASCII
,因?yàn)槟承┙馕龅男枨笮枰?/li>
深入學(xué)習(xí)
看看regex
庫(kù),如果你需要 Unicode 支持,那么這個(gè)更好。