[Python 實戰] - No.12 Python 中的正則表達式使用(1)

1. Python中如何使用正則表達式

Python中使用正則表達式的步驟如下:

  • 使用import re導入正則表達式模塊
  • 使用re.compile()創建一個對象
  • 使用Regex對象的search()方法,傳入一個字符串,然後返回一個Match對象
  • 調用Match對象的group()方法,返回文本中匹配該正則表達式的字符串

示例如下,查找學生姓名中姓Zhang的同學姓名

import re

namelist = "Li Ming;Zhang San;Fu yu;Guo Ji;Ren Jie;Zhang Lin;"
nameRegex = re.compile(r"Zhang\s\w+")
match = nameRegex.search(namelist)
print(match.group())

結果如下:

Zhang San

上面的代碼中,有幾個地方需要解釋一下:

  • re.compile(r"Zhang San\s\w+")在正則表達式的前面加了一個r,標識該字符爲原始字符串。因爲,在Python中,轉義字符前面需要加\來標記,如果你需要在字符串中打出\,那麼你需要使用\\,或者在字符串的前面加入一個r來標記

    r"Zhang San\s\w+""Zhang San\\s\\w+"是等價的

  • search()函數匹配文本中第一個符合該字符串的結果並返回一個Match對象,Match對象的group()函數將返回被查找到的實際文本。所以在上述結果中,我們僅得到Zhang San這個結果。如果你的正則表達式中含有分組(後續會講到),你可以使用group(1), group(2)來查詢正則表達式中第一個,第二個分組的匹配結果。

2. 正則表達式的更多模式
1. 使用括號分組

假設,某地區的電話號碼的表示形式爲123-456-7890的形式,且前三位爲區號,後七位標識電話號,要求將從文本中同時獲取區號,電話號和整體的電話號碼。

代碼和結果如下:

text = "My phone number is 455-789-1234"
pnRegex = re.compile(r"(\d\d\d)-(\d\d\d-\d\d\d\d)")
match = pnRegex.search(text)
print(match.group())
print(match.group(1))
print(match.group(2))
print(match.groups())

結果如下:

455-789-1234
455
789-1234
(‘455’, ‘789-1234’)

group()默認傳入參數爲0,即返回整個匹配的文本。如果想獲取全體分組的結果,使用groups()函數,該函數返回一個包含所有分組匹配結果的元組。

2. 使用管道匹配多個分組

字符|是正則表達式中的管道,用來匹配許多表達式中的一個。如果想匹配姓名列表中,姓Zhang的和姓Li的同學的姓名,可以使用管道|來連接多個正則表達式。

 namelist1 = "Li Ming;Zhang San;Fu yu;Guo Ji;Ren Jie;Zhang Lin;"
 namelist2 = "Zhang San;Fu yu;Guo Ji;Ren Jie;Zhang Lin;Li Ming;"
 nameRegex = re.compile(r"Zhang\s\w+|Li\s\w+")
 match1 = nameRegex.search(namelist1)
 print(match1.group())
 match2 = nameRegex.search(namelist2)
 print(match2.group())

結果如下:

Li Ming
Zhang San

3. 使用問號實現可選匹配

例如在之前的電話匹配中,我們希望即便有人省略區號,依然可以檢測出電話號碼。使用?來實現部分匹配的模式是可選的

text1 = "My phone number is 455-789-1234"
text2 = "My phone number is 789-1234"
pnRegex = re.compile(r"(\d\d\d-)?(\d\d\d-\d\d\d\d)")
match1 = pnRegex.search(text1)
print(match1.group())
match2 = pnRegex.search(text2)
print(match2.group())

結果如下:

455-789-1234
789-1234

4. 使用花括號匹配特定次數

假設現在我們有一串字符串:

* *** ********** ** *** ****** ** ***** * ******* ***** **** ***** * *** * **

如果我們想匹配一下幾種情況:

  • 恰好三個* 連在一起的,如***
  • 少於等於三個* 連在一起的,如**,*
  • 連在一起的*個數大於等於四,但是小於等於五
  • 大於等於六個*連在一起的,如******

代碼如下:

text = "* *** ********** ** **** ****** ** ***** * ******* ***** **** ***** * *** * **"
sRegex1 = re.compile(r"(\*){3}")
sRegex2 = re.compile(r"(\*){,3}")
sRegex3 = re.compile(r"(\*){4,5}")
sRegex4 = re.compile(r"(\*){6,}")
match1 = sRegex1.search(text)
match2 = sRegex2.search(text)
match3 = sRegex3.search(text)
match4 = sRegex4.search(text)
print(match1.group())
print(match2.group())
print(match3.group())
print(match4.group())

結果如下所示:

***
*
*****
**********

r"(\*){3}"中,(\*)表示匹配型字符的分組。因爲 在正則表達式中表示匹配一個或多個,所以需要使用\進行轉義,表示字符 *

花括號{n,m},表示前面的分組重複次數大於等於n次並且小於等於m次。m和n也可省略其中一個,表示大於等於n或者小於等於m。{n}表示分組恰好重複n次。

另外,可以看到,在被匹配的文本中,長度爲4的字符串****排在長度爲5的字符串***** 前面,但是代碼查找到的結果是*****,這是因爲默認情況下正則表達式是貪婪地,花括號的貪婪版本會儘可能的匹配更長的字符串。使用字符?可以聲明正則表達式爲非貪心形式

text = "* *** ********** ** *** ****** **** ***** * ******* ***** **** ***** * *** * **"
sRegex1 = re.compile(r"(\*){4,5}")
match1 = sRegex1.search(text)
sRegex2 = re.compile(r"(\*){4,5}?")
match2 = sRegex2.search(text)
print(match1.group())
print(match2.group())

結果如下:

*****
****
5. findall()方法

re模塊的findall()方法返回被匹配文本中的所有匹配到的結果。

之前提到的search() 僅返回文本中第一個匹配到的結果,方法返回一個Match對象,並調用Match對象的group()函數獲取匹配結果

findall()匹配文本中所有匹配的結果,並且返回一個所有結果的列表。如果正則表達式中有分組,那麼findall()將返回分組的列表

比如之前的電話號的正則表達式:

text = "My phone number is 455-789-1234,Lily's phone number is 110-101-1230 and Lucy's phone number is 789-456-1245"
pnRegex = re.compile(r"(\d\d\d)-(\d\d\d-\d\d\d\d)")
reslist = pnRegex.findall(text)
print(reslist)

結果如下:

[(‘455’, ‘789-1234’), (‘110’, ‘101-1230’), (‘789’, ‘456-1245’)]

正則表達式中的常用字符表,網上資源很多,這裏不再放出來。


P.S. 文章不足之處還望指正
參考書籍:《Python編程快速上手—讓繁瑣工作自動化》

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