看故事學會正則表達式

這這個教程中,我嘗試使用一種故事場景來講解正則表達式,以期能夠爲大家更愉快、更容易地理解。

有一天,小明在用Python做文本清洗的時候,突然覺得“233”太多了,覺得像是在嘲諷自己,怎麼都看不順眼,下定決心要把文本里所有的“233”全部幹掉,於是一場屬於小明和233的戰爭就這樣拉開了帷幕。

一開始,小明直接使用制式武器字符串替換,通過將“233”替換爲空,處理掉了所有的“233”。

str = str.replace("233", "", str)

(以上代碼的打擊面是字符串中包含的所有“233”子字符串)

當他碼放南山、刀槍入庫準備收工的時候,發現“233”居然還有無計其數的同盟,他們有“2333”、“23333”、“233333”……於是,小明取出了無差別平A碾壓攻擊武器正則表達式,準備再次向“233”的所有同盟開火,將這一類的“233”的同盟全部消滅。

str = re.sub("23+", "", str)

(以上代碼的打擊面是字符串中的“23”、“233”、“2333”、“23333”……)

通過這個應用,我們可以簡單地將正則表達式理解爲一種用來描述字符串的字符串(文本模式)。一個正則表達式可以同時對應很多個字符串,例如在上例中,正則表達式"23+"就可以同時對應“233”、“2333“、”23333”……等等。

我們將檢查字符串中是否有可以對應正則表達式的子字符串的過程,稱之爲匹配

在上例所使用的正則表達式中,“+”表示將前一個字符匹配一次或多次,因此“23+”可以匹配“23”、“233”、“2333”……。在正則表達式中,我們將類似“+”的用來描述匹配要求的字符,稱之爲元字符。其中,“+”這類描述匹配次數的元字符,稱爲限制符

類似的,在正則表達式中還有“*”、“+”也用來表示對前一個字符的匹配次數。這類元字符的具體描述如下:

元字符 描述
* 匹配前面的子表達式任意次;例如,“23*”可以匹配“2”、“23”、“233”……
+ 匹配前面的子表達式一次或多次;例如,“23+”不能匹配“2”,但可以匹配“23”、“233”……
? 匹配前面的子表達式零次或一次。例如,“23?”只能匹配“2”和“23”

但是小明突然發現,剛纔的無差別平A碾壓攻擊如果執行,將會誤傷了己方臥底“23”。本着不放棄任何一個兄弟的原則,小明修改了無差別平A碾壓攻擊武器,將”23”從目標範圍中剔除。

str = re.sub("23{2,}", "", str)

(以上代碼的打擊面是字符串中的“233”、“2333”、“23333”……,但不包括“23”)

在上例所使用的正則表達式中,“{2,}”表示至少匹配2次,因此“23{2,}”可以匹配“233”、“2333“但不能匹配”23“。類似的元字符還有”{n}“、”{n,m}“。這類元字符的具體描述如下:

元字符 描述
{n} 匹配前面的子表達式確定的n次;例如,“23{2}”只能匹配“233”……
{n,} 匹配前面的子表達式至少n次;例如,“23{2,}”可以匹配“233”、“2333”……
{n,m} 匹配前面的子表達式n次到m次(其中n<=m)。例如,“23{2,3}”只能匹配“233”和“2333”

就在小明即將按下“攻擊”按鈕時,臥底“23”發來消息,通過他潛伏字符串中間對“233”們的勸說,位於字符串中間的“233”的立場已經動搖了,現在可以確定的仍然是壞數只有在字符串開頭和結尾的“233”,希望先將這些“233”消滅殺雞儆猴。於是小明第一次啓動了無差別平A碾壓攻擊武器,消滅了字符串開頭和結尾的“233”族羣。

str = re.sub("^23{2,}|23{2,}$", "", str)

(以上代碼的打擊面是位於字符串開頭或結尾位置的“233”、“2333”、“23333”……)

在上例所使用的正則表達式中,”^“表示匹配字符串開頭、”$“表示匹配字符串結尾,”|“表示或的意思,因此可以同時匹配在字符串開頭和結尾處的“233”。這類元字符的具體描述如下(請特別注意”|“的影響範圍):

元字符 描述
^ 匹配字符串開頭,例如“^2”在“232”中就只能匹配開頭處的2
$ 匹配字符串結尾,例如“2$”在“232”中就只能匹配結尾處的2
x|y 匹配x或y。例如“2|33”將會匹配“2”和“33”,但不會匹配“23“或“33”;若需要匹配”23“和”33“,需要使用”[2|3]3“

在這一輪的攻擊之後,”233“族羣雖然受到重創,但是其中的一些“233”卻選擇了反擊。公然打出”小明2333“、”233小明“等標語嘲諷小明,小明不堪其擾;但是因爲臥底“23”仍然在勸降,不希望打擊面過廣。因此,小明決定針對這些點名嘲諷小明的“233”採取定點打擊,同時在打擊過程中不能誤傷到自己的名字。

str = re.sub("(?<=小明)23{2,}|23{2,}(?=小明)", "", str)

(以上代碼的打擊面是:“小明233”中的“233“,”233小明“中的”233“……)

在上例使用的正則表達式中:

“(?<=小明)”表示在匹配到的“233”應該是緊接着”小明“之後的,不要前面沒有”小明“的”233“;但是匹配的結果只是”233“自己,前面的“小明”只是判斷條件,並不匹配到結果中。

而“(?=小明)”則表示在已經匹配到的“233”之後應該緊跟着“小明”,不要後面沒有“小明”的“233”;但是匹配的結果也只有“233”自己,後面的“小明”也只是判斷條件,並不匹配到結果中。

這種不匹配到結果,而是用作判斷條件的匹配我們稱之爲非獲取匹配。非獲取匹配的具體描述如下:

元字符 描述
(?=pattern) 正向肯定預查,在任何匹配pattern的字符串開始處匹配查詢字符串。例如,“233(?=小明)”可以匹配在"233小明“中的”233“,但不能匹配”233小紅“中的”233“
(?<=pattern) 反向肯定預查,與正向肯定預查的方向相反。例如”(?<=小明)233“可以匹配”小明233“中的”233“,但不能匹配”小紅233“中的”233“
(?!pattern) 正向否定預查,在任何不匹配pattern的字符串開始出匹配查詢字符串。例如”233(?!小明)“可以匹配”233小紅“中的”233“,但不能匹配”233小明“中的”233“
(?<!pattern) 反向否定預查,與反向肯定預查的方向相反。例如”(?<!小明)233“可以匹配”小紅233“中的”233“,但不能匹配”小明233“中的”233“

在這一次的定點打擊後,剩餘的大部分”233“都成功被臥底“23”勸降了,改成”666“不再嘲諷小明瞭。但是其中還是有一些”233“開始隱藏自己,有的改成了”2A333“,有的改成了”2c333“,爲了進一步消滅這些”233“,小明再一次調整 了無差別平A碾壓攻擊武器,對這類”233“進行打擊。

str = re.sub("2[A-Za-z]?3{2,}", "", str)

(以上代碼的打擊麪包括“2A33”、“2a33”、“2B33”、“2b33”……)

在上例使用的正則表達式中,“[A-za-z]”表示匹配任意大寫或小寫的英文字母,因此可以匹配在“2”和“33”之間添加了英文字母的”233“。類似的元字符具體描述如下:

元字符 描述
[xyz] 匹配”x“、”y“、”z“中的任意一個字符,稱爲字符集合
[^xyz] 匹配除了”x“、”y“、”z“以外的任意一個字符,稱爲負值字符集合
[a-z] 匹配“a“到”z“範圍內的任意一個字符,即所有英文小寫字符,稱爲字符範圍
[^a-z] 匹配除了“a“到”z“範圍內的字符以外的任意一個字符,稱爲字符範圍

其中同一個方括號中可以包含多個字符範圍,例如“[A-Za-z]”,其中的每一個字符範圍都能起作用。

經過這一次的打擊,仍然隱藏着的“233”非常恐懼,他們選擇進一步隱藏自己,將製表符、換行符之類不可見的字符加到了2和3之間,形成了諸如“2\t33”、“2\n33”之類深度變形的“233”。但是小明作爲不懂英文還可以和外國筆友交流的優秀學生,決定對這些利用不可見字符深度隱藏的“233”進行打擊。

str = re.sub("2\s?3{2,}", "", str)

(以上代碼的打擊麪包括“2\t33”、“2\n33”、“2\r33”……)

在正則表達式中,“\”表示轉義,即多種編程語言中轉移字符的概念。例如“\\”匹配“\”;“\\n”匹配“\n”,而“\n”則匹配換行符。轉義符及其他通過轉義符表示的字符的詳細描述如下:

元字符 描述
\ 轉義標誌符,將下一個字符轉義。
\f 匹配換頁符
\n 匹配換行符
\r 匹配回車符
\t 匹配製表符
\v 匹配垂直製表符

在上例使用的表達式中,“\s”表示匹配任意不可見字符,包括空格、換行符、製表符等;這是一個通配符,等價於”[ \f\r\n\t\v]“。其他通配符的詳細描述如下:

元字符 描述
. 匹配除“\r”和“\n”以外的任意單個字符
\b 匹配單詞邊界的位置,即單詞和空格間的位置
\B 匹配非單詞邊界的位置
\d 匹配數字字符
\D 匹配非數字字符
\s 匹配任意不可見的字符,等價於”[ \f\r\n\t\v]“
\S 匹配任意可見的字符
\w 匹配包含下劃線的任意單詞字符
\W 匹配非單詞字符

經過多次對“233”的打擊,“233"向小明表示無條件投降,並將所有“233”均改爲“666”,小明與“233”的戰爭終於結束。

至此,絕大多數的正則表達式元字符都已經被介紹過了,這些元字符在學習之初並不需要全部都記下來,可以在使用的時候查表,多用用慢慢就熟了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章