看一次就會的python正則表達式的使用指南

前言

正則表達式作爲一名合格的程序員的必備的基本技術之一,其有用性不言而喻。但是它爲什麼會非常難以掌握,甚至想用一用也都感覺難以下手呢?本文將會讓你一次就看會如何使用Python正則表達式。

1. 正則表達式的組成

在介紹如何使用Python的正則表達式時,我們需要先認識一下正則表達式的各種功能,以及其組成形式如何。

正則表達式可以從非結構化的文本中提取到我們想要的內容,其本質爲模式匹配,也是體現出智能化的最初手段,現在已經廣泛應用於自動化處理信息的流程之中,從爬蟲到人工智能,無處不在,其需求也是相當的大。

一提及正則表達式的編寫,在N多的博客裏都提到了一個神奇的網站http://www.txt2re.com/,這個網站我之前也用過,如果你不會正則表達式,又想偷懶自動生成,你只需要在這個網站裏複製粘貼一個最複雜的情況,然後把你想匹配的內容通過可視化的點擊組合就可以自動生成你想要的正則表達式。

但是遺憾的是,這個網站目前已經打不開了。這也正是告訴我們,核心技術掌握在自己手裏纔是真啊。現在我們來看看正則表達式該如何編寫。下面是使用進行正則表達式的一般流程,不同的語言其實現方法不完全相同,我們今天主要聚焦與使用python進行正則表達式的三種匹配方式,以獲得我們想要的目標片段,對於其他方法,我們以後再進行講解。

  1. 首先確定你的輸入的大致格式
  2. 在這個輸入的大致格式中定位到你需要的內容,以及你不需要的內容。
  3. 通過正則表達式將其匹配出來
  4. 抽取其臨時的結果將其保存到我們需要的數據結構中

2. 使用python表示正則表達式流程

如果我們使用python進行一個正則表達式正則時,我們主要經歷一下幾個步驟:

  1. 導入包
  2. 根據需求指定正則表達式
  3. 編譯自定義的表達式
  4. 根據其表達式進行匹配
  5. 輸出結果

1,3,5都是相對容易的部分,而其中最難的部分主要有兩步,一個是制定一個符合需求的正則表達式,另一個則是如何進行匹配。我們最後會簡單的介紹一下輸出結果。

3. 編寫正則表達式

編寫正則表達式是其中的核心,如何編寫正確的,符合我們想法的表達式呢?我們這裏介紹下面兩個部分進行構建:

原封不動的單詞
這一部分並不是我們需要的,只是一些留存在我們需要的內容中間的部分。原封不動的單詞就原封不動的抄寫上去,不要增加格外的形式。

待匹配的部分
這一部分使我們想抽取出的內容,將我們想匹配的部分使用正則表達式進行表達分爲兩個部分,一個部分爲我們的匹配的字符,例如:

\w 匹配字母數字及下劃線
\W 匹配非字母數字及下劃線
\s 匹配任意空白字符,等價於 [\t\n\r\f].
\S 匹配任意非空字符
\d 匹配任意數字,等價於 [0-9].
\D 匹配任意非數字
\A 匹配字符串開始
\Z 匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串。
\z 匹配字符串結束
\G 匹配最後匹配完成的位置。
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B 匹配非單詞邊界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\n, \t, 等. 匹配一個換行符。匹配一個製表符。等
\1…\9 匹配第n個分組的內容。
\10 匹配第n個分組的內容,如果它經匹配。否則指的是八進制字符碼的表達式。

另一種,則是匹配的模式,決定我們如何進行匹配:

^ 匹配字符串的開頭
$ 匹配字符串的末尾。
. 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符。
[…] 用來表示一組字符,單獨列出:[amk] 匹配 ‘a’,‘m’或’k’
[^…] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re* 匹配0個或多個的表達式。
re+ 匹配1個或多個的表達式。
re? 匹配0個或1個由前面的正則表達式定義的片段,非貪婪方式
re{ n} 精確匹配 n 個前面表達式。例如, o{2} 不能匹配 “Bob” 中的 “o”,但是能匹配 “food” 中的兩個 o。
re{ n,} 匹配 n 個前面表達式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。“o{1,}” 等價於 “o+”。“o{0,}” 則等價於 “o*”。
re{ n, m} 匹配 n 到 m 次由前面的正則表達式定義的片段,貪婪方式
a| b 匹配a或b
(re) 對正則表達式分組並記住匹配的文本
(?imx) 正則表達式包含三種可選標誌:i, m, 或 x 。隻影響括號中的區域。
(?-imx) 正則表達式關閉 i, m, 或 x 可選標誌。隻影響括號中的區域。
(?: re) 類似 (…), 但是不表示一個組
(?imx: re) 在括號中使用i, m, 或 x 可選標誌
(?-imx: re) 在括號中不使用i, m, 或 x 可選標誌
(?#…) 註釋.
(?= re) 前向肯定界定符。如果所含正則表達式,以 … 表示,在當前位置成功匹配時成功,否則失敗。但一旦所含表達式已經嘗試,匹配引擎根本沒有提高;模式的剩餘部分還要嘗試界定符的右邊。
(?! re) 前向否定界定符。與肯定界定符相反;當所含表達式不能在字符串當前位置匹配時成功
(?> re) 匹配的獨立模式,省去回溯。

兩者搭配即可完成我們想要的結果,雖然這裏列舉了很多,但是我們常用的就那幾個,正則表達式的簡單劃分將正則表達式劃分爲元字符、反義、量詞和懶惰限定詞。我會在後面的部分給出一個實例。當我們的正則表達式撰寫完畢後,我們使用下面的函數獲得我們的匹配模板。

re.compile(pattern[, flags])

4. 匹配的方式

正則表達式匹配的方式主要有3種match, searchfindall。如果你懂英語的話,就知道它們的區別,這裏前兩個都是單一匹配,只會匹配一個流程,如果有多個符合匹配規則的,它們只會返回第一個結果,而findall會把所有符合候選的都匹配出來。而前兩個的區別就是match必須是開頭就要能夠匹配,也就是和startwith差不多的效果,而search則可以在任意位置進行匹配。

下面看一下三個方法的參數表示,其中pattern爲我們制定的正則表達式,string爲我們要匹配的字符串,flags表示匹配模式:

re.match(pattern, string, flags=0)
re.search(pattern, string, flags=0)
findall(string[, pos[, endpos]])

因此我們選擇方式時有以下幾個步驟:

  1. 是否需要匹配多個?是,選擇findall
  2. 是否需要從頭匹配?是,選擇match
  3. 一般情況使用search

5. 匹配結果展示

匹配結果展示主要有以下四個部分組成:

group([group1,]) 方法用於獲得一個或多個分組匹配的字符串,當要獲得整個匹配的子串時,可直接使用 group() 或 group(0);
start([group]) 方法用於獲取分組匹配的子串在整個字符串中的起始位置(子串第一個字符的索引),參數默認值爲 0;
end([group]) 方法用於獲取分組匹配的子串在整個字符串中的結束位置(子串最後一個字符的索引+1),參數默認值爲 0;
span([group]) 方法返回 (start(group), end(group))

例如下面這個例子,主要表現了我們如何調用這四個部分。

>>>import re
>>> pattern = re.compile(r'\d+')                    # 用於匹配至少一個數字
>>> m = pattern.match('one12twothree34four')        # 查找頭部,沒有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 從'e'的位置開始匹配,沒有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 從'1'的位置開始匹配,正好匹配
>>> print m                                         # 返回一個 Match 對象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0)   # 可省略 0
'12'
>>> m.start(0)   # 可省略 0
3
>>> m.end(0)     # 可省略 0
5
>>> m.span(0)    # 可省略 0
(3, 5)

6. 舉一個簡單的例子

一個更好的,更直觀易懂的方法是如下這個例子,相比較剛纔使用數字索引,它將每一個匹配內容語義化,使得代碼更加容易理解。

contactInfo = '  ( Nucleus (span 2 3) (rel2par span)'
pattern=re.compile(r'(?P<nuclearity>\w+) \(span (?P<start>\w+) (?P<end>\w+)\) \(rel2par (?P<relation>\w+)\)')
match = pattern.search(contactInfo)
print(match.group())  # Nucleus (span 2 3) (rel2par span)
print(match.group("nuclearity"))  # Nucleus 
print(match.group("start"))  # 2
print(match.group("end"))  # 3
print(match.group("relation"))  # span

從上述的例子中我們就可以獲得最直觀的結果,我們只需要將這些結果存入到我們需要的數據結構中即可。

7. 其他一些補充知識

7.1 匹配常用的一些格式

如果我們只需要匹配一些常用的格式,如姓名、身份證、郵箱、電話號碼等,都是有現成的工具直接生成,不需要我們進行再次編寫。

7.2 匹配中文字符

如果你只是想匹配若干個中文漢字,使用下面的正則表達式:

[\u4E00-\u9FA5\\s]+ 多個漢字,包括空格
[\u4E00-\u9FA5]+ 多個漢字,不包括空格
[\u4E00-\u9FA5] 一個漢字

這裏還有匹配更全的中文字的方法

7.3 匹配一些特殊符號

正則表達式的各種括號的用處以及如何進行括號的匹配

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