1. 程式人生 > 其它 >Python3使用re模組解析正則表示式

Python3使用re模組解析正則表示式

正則表示式是程式語言中一種重要的功能,用於按指定規則從文字中匹配出指定的值。

正則表示式元字元

模式 描述
^ 匹配字串的開頭
$ 匹配字串的末尾。
. 匹配任意字元,除了換行符,當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
(re) 匹配括號內的表示式,也表示一個組
(?imx) 正則表示式包含三種可選標誌:i, m, 或 x 。隻影響括號中的區域。
(?-imx) 正則表示式關閉 i, m, 或 x 可選標誌。隻影響括號中的區域。
(?: re) 類似 (...), 但是不表示一個組
(?imx: re) 在括號中使用i, m, 或 x 可選標誌
(?-imx: re) 在括號中不使用i, m, 或 x 可選標誌
(?#...) 註釋.
(?= re) 前向肯定界定符。如果所含正則表示式,以 ... 表示,在當前位置成功匹配時成功,否則失敗。但一旦所含表示式已經嘗試,匹配引擎根本沒有提高;模式的剩餘部分還要嘗試界定符的右邊。
(?! re) 前向否定界定符。與肯定界定符相反;當所含表示式不能在字串當前位置匹配時成功。
(?> re) 匹配的獨立模式,省去回溯。
\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.findall()

例如,有一段文字'name: Kevin age: 18 mobile: 12112345678' ,我們想提取其中的手機號。
已知,手機號碼是11位的數字,我們可以用正則表達的指定格式\d{11}來描述這個規則,\d表示匹配數字,{11}表示前一項重複11次,示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678' 
patten = '\d{11}'  # 匹配11個數字
print(re.findall(patten, txt))

re.findall()方法,根據匹配規則去目標文字中查詢,將找到的所有符合這個格式的組合位一個列表,如果沒有符合匹配的項則返回空列表。執行結果如下:

['12112345678']

re.search()

除使用re.findall()找到所有的外,我們還可以使用re.search()查詢一個,示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678'
patten = '\d{11}'  # 匹配11個數字

result = re.search(patten, txt)
if result is not None:  # 必須判斷匹配結果不為None才能使用下面的group方法
    print(result.group())  # 使用group方法獲取第一個匹配結果

執行結果如下:

12112345678

re.match()

re.search()是搜尋目標字串的部分項,我們還可以使用re.match對整個字串形式進行匹配,示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678'

# 符合目標文字完整樣式的匹配規則 
patten = 'name: \w+ age: \d+ mobile: \d{11}'  

result = re.match(patten, txt)
if result is not None:  # 必須判斷匹配結果不為None才能使用下面的group方法
    print(result.group())  # 使用group方法獲取第一個匹配結果

其中,\w指字母或數字,+表示一個或多個前一項,即姓名匹配一個或任意多個字母或數字。
年齡 \d+則匹配一個或多個數字。
手機號碼\d{}11固定匹配11位數字。執行結果如下:

name: Kevin age: 18 mobile: 12112345678

分組及命名分組

上例中如果我們相對匹配的不同資訊進行提取,如我們只需要姓名Kevin、年齡18及手機號12112345678。則可以對匹配表示式中用小括號(匹配規則)進行分組,示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678'

patten = 'name: (\w+) age: (\d+) mobile: (\d{11})'  # 分組匹配

result = re.match(patten, txt)
if result is not None:  # 必須判斷匹配結果不為None才能使用下面的group方法
    print('姓名', result.group(1))  # 獲取第1個匹配
    print('年齡', result.group(2))  # 獲取第2個匹配
    print('手機號', result.group(3))  # 獲取第3個匹配

執行結果如下:

姓名 Kevin
年齡 18
手機號 12112345678

當有多個匹配時,我們還可以對分組進行命名,格式為(?P<分組名>匹配規則),示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678'

patten = 'name: (?P<name>\w+) age: (?P<age>\d+) mobile: (?P<mobile>\d{11})'  # 分組匹配

result = re.match(patten, txt)
if result is not None:  # 必須判斷匹配結果不為None才能使用下面的group方法
    print('姓名', result.group('name'))  # 獲取第1個匹配
    print('年齡', result.group('age'))  # 獲取第2個匹配
    print('手機號', result.group('mobile'))  # 獲取第3個匹配

執行結果同上。

re.complie()

當一個匹配規則patten經常要使用時,我們可以使用re.comple()先將該規則進行編譯,然後直接使用編譯後的規則進行匹配。示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678'

patten = re.compile('name: (?P<name>\w+) age: (?P<age>\d+) mobile: (?P<mobile>\d{11})')  # 編譯匹配規則

result = patten.match(txt)  # 使用該匹配規則進行匹配

if result is not None:  # 必須判斷匹配結果不為None才能使用下面的group方法
    print('姓名', result.group('name'))  # 獲取第1個匹配
    print('年齡', result.group('age'))  # 獲取第2個匹配
    print('手機號', result.group('mobile'))  # 獲取第3個匹配

執行結果同上。

re.sub

替換指定規則字串,字串的replace()方法只能對已知字串進行替換,而re.sub則可以根據匹配規則進行替換。示例如下:

import re

txt = 'name: Kevin age: 18 mobile: 12112345678'  
patten = '\d{11}'
txt = re.sub(patten, '19122229999', txt)  # 替換裡面的11位數字
print(txt)

執行結果如下:

name: Kevin age: 18 mobile: 19122229999

跨行匹配

  • re.M:多行匹配模式,逐行進行匹配
  • re.S: 單行匹配模式,把多行字串視為包含換行符'\n'的單行字串進行匹配

貪婪匹配和非貪婪匹配

貪婪匹配和非貪婪匹配,當一個較長的字串滿足匹配規則和一個較短的字串也滿足相同的匹配規則時選取較長匹配還是較短匹配的問題。

  • 貪婪匹配:匹配符合規則的最長字串;
  • 非貪婪匹配:匹配符合規則的最短字串;
import re

txt = '''name: Kevin age: 18 mobile: 12112345678 name: Lily age: 17 mobile: 19234568712'''

patten = 'name: (.*) age'  # 匹配姓名,預設貪婪匹配
print('預設貪婪匹配', re.findall(patten, txt))

patten = 'name: (.*?) age'  # 加上?表示非貪婪匹配
print('非貪婪匹配', re.findall(patten, txt))

其中.表示匹配任意字元,*表示重複任意多次,?則表示匹配0次或1次。
由於貪婪匹配會匹配最長的字串,所以patten中的age會匹配到Lily後到age,執行結果如下:

 預設貪婪匹配 ['Kevin age: 18 mobile: 12112345678 name: Lily']
 非貪婪匹配 ['Kevin', 'Lily']
                            |