跳至內容

用戶:Xyy23330121/Python/正則表達式

來自維基學院


正則表達式是處理、分割字符串的重要工具。它可以以一定的模式對字符串進行「匹配」,從而可以按模式篩選字符串或子字符串,並對篩選結果進行操作。

Python 專屬的正則表達式語法

[編輯 | 編輯原始碼]

以下語法中,一部分為 Python 的正則表達式專屬。在其它的正則表達式實現中使用可能會出錯。

基本匹配

[編輯 | 編輯原始碼]

正則表達式中,大多數字符都只匹配其自身。比如:正則表達式中 t 會唯一的匹配字符 t,而正則表達式 e 會唯一的匹配字符 e等等。

正則表達式滿足相加性質。即當「正則表達式A」匹配「字符串a」,而「正則表達式B」匹配「字符串b」時。拼接 A 和 B 得到的「正則表達式A+B」,一定匹配拼接得到的「字符串a+b」。

比如,正則表達式 test 會唯一的匹配字符串 test

元字符

[編輯 | 編輯原始碼]

對於正則表達式而言,上面的「基本匹配」是不足以滿足「按模式匹配」的需要的。為了描述模式,正則表達式設置了以下的元字符:

. ^ $ * + ? { } [ ] \ | ( )

這些元字符在正則表達式中表示特殊的意思,從而也就不能匹配字符串中相同字符。元字符之外的字符,都只匹配其自身。

以下將講解元字符的用法。

^ 字符串開頭

[編輯 | 編輯原始碼]

匹配位於字符串開頭的空字符串。比如:

  • 正則表達式 a 和字符串 aba 匹配,會得到兩個子字符串 a
  • 而正則表達式 ^a 和字符串 aba 匹配,只會匹配到位於字符串開頭的子字符串。

$ 字符串末尾

[編輯 | 編輯原始碼]

匹配字符串末尾的空字符串,如果字符串末尾是換行符,也可以匹配該換行符前的空字符串。

\ 轉義字符

[編輯 | 編輯原始碼]

通過 \,我們可以在正則表達式轉義出匹配元字符的表達式。比如:

  • \[ 唯一地匹配字符 [
  • \\ 唯一地匹配字符 \

創建正則表達式時,是通過字符串來創建的。如果要創建正則表達式 \\,需要使用字符串 "\\\\"r"\\"。為了簡便和易於閱讀,在創建正則表達式時,請務必使用「原始字符串」的方式。

字符串的轉義

[編輯 | 編輯原始碼]

Python 字符串支持的、以下轉義序列也被用作正則表達式的轉義。

轉義字符 含義
\a 響鈴(BEL)
\b 退格(BS)
\f 換頁(FF)
\n 換行(LF)
\r 回車(CR)
\t 橫向制表符(TAB)
\v 縱向制表符(VT)
\ooo 八進制數ooo所表示的字符
\xhh 二位十六進制數hh所表示的字符
\N{name} Unicode 數據庫中,名為name的字符,
name可以為別名。有些別名不被支持。
\uxxxx 四位十六進制數xxxx所表示的字符
\Uxxxxxxxx 八位十六進制數xxxxxxxx表示的字符

特別的,以下幾種方式與字符串中的使用有區別:

  • 對於 \ooo,只有以下兩種方式會被視為此轉義:
    • 首位數字是 0,比如 \01
    • 使用了完整的三位數字,比如 \123
  • 對於 \b,只有在「字符類」中,才認為是退格符。
  • 對於 \uxxxx\Uxxxxxxxx\N{name},僅在 Unicode 字符串模式才會被識別。

其它轉義

[編輯 | 編輯原始碼]
轉義 解釋
\A 只匹配字符串開頭
\b 只匹配單詞開頭或結尾
單詞開頭和結尾被定義為:
  • \w\W 之間的空字符串
  • 或者 \w 和字符串開頭或結尾之間的空字符串
\B 非 \b 的空字符串
\Z 只匹配字符串結尾

關於 \w\W,參見下面 ASCII 模式和 Unicode 模式 章節。

[...] 字符類

[編輯 | 編輯原始碼]

[] 括住的部分為字符類。字符類會匹配任何在類中的字符,比如:[aA1] 能匹配三個字符串:aA1

\以外的元字符在字符類中都不起作用。比如:[$] 會唯一的匹配字符 $

如果要添加 ] 到字符類中,則必須要使用轉義方法 \]

除上述規則以外,為簡便起見,字符類有以下的特殊的表示方式:

字符類:「-」

[編輯 | 編輯原始碼]

- 可以在字符類中表示「範圍」,比如:

  • [a-c] 能匹配 abc
  • [a-zA-Z0-9] 能匹配任何單個英文字母字符。

需要注意的是,如果把 - 放在首尾,則不會表示「範圍」,而是表示單獨的 - 字符。比如:

  • [-a] 能匹配 -a
  • [-a-c] 能匹配 -abc

字符類:「^」

[編輯 | 編輯原始碼]

若字符類中第一個字符為 ^,則認為是對字符類取反,比如:

  • [^a] 能匹配任何不是 a 的字符。
  • [^a-z] 能匹配任何不是小寫英文字母的字符。

需要注意的是,如果把 ^ 放在中間,則沒有此效果,比如:

  • [ ^] 能匹配空格字符和 ^

. 任意字符

[編輯 | 編輯原始碼]

. 可以匹配除了換行符以外的任意字符。

重複匹配

[編輯 | 編輯原始碼]

通過以下的方式,可以設定匹配次數。

* 匹配任意次

[編輯 | 編輯原始碼]

正則表達式 ab* 會匹配字符串 aababb 等。

+ 匹配 >=1 次

[編輯 | 編輯原始碼]

正則表達式 ab+ 會匹配字符串 ababb 等。但不會匹配 a

? 匹配 0 或 1 次

[編輯 | 編輯原始碼]

正則表達式 ab? 會匹配字符串 a 和字符串 ab

{m} 匹配 m 次
[編輯 | 編輯原始碼]

比如:正則表達式 a{3} 會匹配字符串 aaa

使用 a{m} 時,m 必須是正整數。

{m,n} 匹配 m ~ n 次
[編輯 | 編輯原始碼]

m 和 n 必須是正整數。

比如:正則表達式 a{2,3} 會匹配字符串 aa 和字符串 aaa

特別的,使用 {,n} 會匹配 0 ~ n 次。使用 {m,} 會匹配 m ~ 任意次。使用 {,} 等同於使用 *

重複匹配算法

[編輯 | 編輯原始碼]

在進行重複匹配時,默認會先儘可能多地進行匹配。在正則表達式 ^[a-z]*reabrer進行匹配時,會進行以下步驟:

  • [a-z]* 匹配 abrer
    • r 到字符串末尾,無法匹配,回退
  • [a-z]* 匹配 abre
    • r 匹配 r
    • e 到字符串末尾,無法匹配,回退
  • [a-z]* 匹配 abr
    • r 無法匹配 e ,回退
  • [a-z]* 匹配 ab
    • r 匹配 r
    • e 匹配 e
    • 正則表達式結束,匹配完畢,匹配到子字符串 abre

可以看出 [a-z]* 會先嘗試匹配 5 個字符、再嘗試匹配 4 個字符,從匹配字符數從多到少進行嘗試。這種嘗試的模式被稱為「貪婪模式」。

? 非貪婪模式

[編輯 | 編輯原始碼]

在代表重複匹配的結構後添加 ? ,則會改為匹配字符數從少到多進行嘗試。

比如,在正則表達式 ^[a-z]*?reabrer進行匹配時,會進行以下步驟:

  • [a-z]*? 匹配 a
    • r 無法匹配 b ,回退
  • [a-z]*? 匹配 ab
    • r 匹配 r
    • e 匹配 e
    • 正則表達式結束,匹配完畢,匹配到子字符串 abre

+ 佔有模式

[編輯 | 編輯原始碼]

在代表重複匹配的結構後添加 + ,則會在貪婪模式的基礎上,不允許回退。這也被稱為「佔有模式」。

比如,在正則表達式 ^a?[a-z]*+reabrer進行匹配時,會進行以下步驟:

  • a? 匹配 a
    • [a-z]*+ 匹配 brer 並「佔有」
      • r 無法匹配字符串末尾,回退
        不能回退並修改[a-z]*+的匹配結果
        回退並修改在[a-z]*+之前的a?
  • a? 匹配空字符串
    • [a-z]*+ 匹配 abrer 並「佔有」
      • r 無法匹配字符串末尾,回退
        不能回退並修改[a-z]*+的匹配結果
  • 正則表達式結束,匹配完畢,沒有匹配到字符串。

「佔有模式」和「非貪婪模式」不能同時設置。

正則表達式 a|b 會匹配字符串 ab

特別的,如果左邊的「分支」匹配成功了,就不會嘗試對右邊的分支進行匹配。比如:

[a-z]*|[0-9]*114 和字符串進行匹配時,會先匹配 [a-z]*114,匹配失敗後再嘗試匹配 [0-9]*114。如果 [a-z]*114 匹配成功,就不會嘗試 [0-9]*114 了。舉個例子:

  • [a-z]*|[0-9]*1141140114 匹配:
    • 嘗試匹配 [a-z]*114
      • [a-z]* 匹配到空字符串
        • 114 匹配到 114
          匹配成功,匹配到 114

在匹配過程中,根本不會嘗試匹配 [0-9]*114。即便 [0-9]*114 能匹配完整的 1140114

(...) 組合

[編輯 | 編輯原始碼]

我們可以把一系列正則表達式作成組合,並對組合進行操作。比如:

  • 正則表達式 (ab)? 會匹配字符串 ab 和字符串 abab
  • 正則表達式 (ab)|c 會匹配字符串 ab 和字符串 c
匹配方式字符
字符 匹配方式
i 忽略大小寫
m 允許多行匹配
s . 會匹配任意字符
(包括換行符)
x 帶註釋的正則表達式
a ASCII 模式
u Unicode 模式
L 按本地語言區域模式

(?imsxauL) 設置匹配方式

[編輯 | 編輯原始碼]

以上的匹配方式並不絕對。如果在正則表達式中,出現了形如 (?a) 的組,則會按照該組的內容設置匹配方式。

這種類型的組不會匹配任何內容,它只匹配空字符串。

右表列出了該組中,可用的字符。這些字符可以進行組合,以同時設置多個匹配方式。

其中,ASCII 模式、 Unicode 模式和「按本地語言區域」模式互相矛盾,因此不能相互組合。在未設置這些模式時,默認使用 Unicode 模式。「按本地語言區域」的模式不可靠,不建議使用。

ASCII 模式和 Unicode 模式

[編輯 | 編輯原始碼]

ASCII 模式和 Unicode 模式設置以下轉義得到的字符類的行為:

轉義 ASCII 模式 Unicode 模式
\d [0-9] 任何屬於 Unicode 字符類別 ND 的字符。
\D [^0-9] 任何非 \d 的字符。
\s [ \t\n\r\f\v] 任何 Unicode 空白字符
\S [^ \t\n\r\f\v] 任何非 Unicode 空白字符
\w [a-zA-Z0-9_] 任何 str.isalnum() 方法返回 True 的字符
以及下劃線
\W [^a-zA-Z0-9_] 任何 str.isalnum() 方法返回 False 的字符
不包含下環線

多行匹配

[編輯 | 編輯原始碼]

多行匹配模式會影響 ^$ 的行為。

在設置了多行匹配模式後:

  • ^ 會匹配位於換行符後的空字符串。
  • $ 會匹配位於換行符前的空字符串。

帶註釋的正則表達式

[編輯 | 編輯原始碼]

此時,允許創建帶有註釋的、美觀的正則表達式。以下兩種方式得到的結果是相同的:

pattern = r"(0b[01]*)|(0o[0-7]*)|([0-9]*)|(0x[0-9a-fA-F]*)"
r = re.compile(pattern) #编译正则表达式
pattern = r"""(?x) #匹配数字:
  (0b[01]*)          #二进制数字
| (0o[0-7]*)         #八进制数字
| ([0-9]*)           #十进制数字
| (0x[0-9a-fA-F]*)   #十六进制数字
"""
r = re.compile(pattern) #编译正则表达式

此時,正則表達式會忽略字符串中的空格,以及多行字符串中、自動加入的換行符。

如果要匹配空格,則使用 \ 。如果要匹配換行符,則使用 \n

(?imsxauL-imsx:...) 設置局部匹配方式

[編輯 | 編輯原始碼]

僅對其中的正則表達式啟用或棄用某匹配方式。比如:

  • (?i)ab 會匹配:abAbaBAB
  • (?i)a(?-i:b) 會匹配:abAb。棄用了對 b 的「忽略大小寫模式」。
  • a(?i:b) 會匹配:aBAB。僅對 b 啟用「忽略大小寫模式」。

特別的,不允許簡單地棄用「ASCII 模式」「Unicode 模式」和「按本地語言區域模式」。

(?>...) 佔有模式

[編輯 | 編輯原始碼]

該組會對組中的表達式啟用「佔有模式」,比如:

  • x*+ 等同於 (?>x*)

(?:...) 非捕獲模式

[編輯 | 編輯原始碼]

此方法會影響 Python 在進行匹配時、保存的結果。比如:

  • (xyz) 在匹配時,會在結果中保存匹配到的 xyz
  • (?:xy(z)) 在匹配時,會匹配到相同的內容,但結果中僅保存 z

(?P<name>...) 帶命名的組

[編輯 | 編輯原始碼]

通過這種方式,可以給組進行命名。re.Match 實例的多個方法,以及 re.Pattern 實例的 sub 方法會引用命名組匹配到的內容。

被命名的組可以用以下方式,在正則表達式中引用。

(?P=name)

[編輯 | 編輯原始碼]

僅匹配第一次匹配到 (?P<name>...) 時、匹配到的內容。

import re
p = re.compile(r'''(?x)
<(?P<ele_name>[a-zA-Z]+).*?> #匹配<html>
.*                           #匹配中间
</(?P=ele_name)>             #匹配</html>
''')
s = '<p>Paragraph</pi>'
s1 = '<p>Paragraph</p>'

print(p.match(s).string[matchobj.start():matchobj.end()])  #输出空字符串,没有得到匹配。
print(p.match(s1).string[matchobj.start():matchobj.end()]) #输出:<p>Paragraph</p>

類似 (?P=name) ,但此方式也可以用於引用一般的組。

僅匹配第一次匹配到第 num 個組時,匹配到的內容。

(?#...) 註釋

[編輯 | 編輯原始碼]

作為註釋使用,僅匹配空字符串。

(?=...) 前視斷言

[編輯 | 編輯原始碼]

僅匹配空字符串。

其中的正則表達式和當前位置右側的內容相匹配,則匹配空字符串成功。否則匹配失敗。

比如:正則表達式 Isaac(?= Newton) 將會匹配 Isaac Newton 中的 Isaac,但不會匹配 Isaac Brown 中的 Isaac

這種方式被稱為前視斷言 (lookahead assertion)。

(?!...) 否定型前視斷言

[編輯 | 編輯原始碼]

僅匹配空字符串。

其中的正則表達式和當前位置右側的內容不匹配,則匹配空字符串成功。否則匹配失敗。

比如:正則表達式 Isaac(?! Newton) 將會匹配 Isaac Brown 中的 Isaac,但不會匹配 Isaac Newton 中的 Isaac

這種方式被稱為否定型前視斷言 (negative lookahead assertion)。

(?<=...) 肯定型後視斷言

[編輯 | 編輯原始碼]

僅匹配空字符串。

其中的正則表達式與當前位置左側的內容相匹配,則匹配空字符串成功。否則匹配失敗。

這種方式被稱為肯定型後視斷言 (positive lookbehind assertion)。

(?<!…) 否定型後視斷言

[編輯 | 編輯原始碼]

僅匹配空字符串。

其中的正則表達式和當前位置左側的內容不匹配,則匹配空字符串成功。否則匹配失敗。

這種方式被稱為否定型後視斷言 (negative lookbehind assertion)。

(?(num/name)yes-pattern|no-pattern) 條件匹配

[編輯 | 編輯原始碼]

在匹配時,之前已有的、\num(?P=name) 所示的組、匹配的並非空字符串,則按照 yes-pattern 進行匹配。否則,按照 no-pattern 進行匹配。

Python 使用正則表達式

[編輯 | 編輯原始碼]
旗標列表
旗標 匹配方式
re.I
re.IGNORECASE
忽略大小寫
re.M
re.MULTILINE
允許多行匹配
re.S
re.DOTALL
. 會匹配任意字符
(包括換行符)
re.X
re.VERBOSE
帶註釋的正則表達式
re.A
re.ASCII
ASCII 模式
re.U
re.UNICODE
Unicode 模式
re.L
re.LOCALE
按本地語言區域模式
re.NOFLAG 表示空旗標。
特別的:re.NOFLAG 就是整數 0
re.DEBUG 顯示有關編譯表達式的調試信息。

旗標和上述 設置匹配方式 章節的效果是相同的。右表列出了可用的旗標。

在使用旗標時,可以用「按位或」運算符 | 組合多個旗標,並把結果傳入下面函數中的 flags 參數中。

特別的:re.NOFLAG 和任何其它旗標進行組合,都會返回其它旗標。

re.DEBUG 會在使用正則表達式時,返回編譯的結果。

re.compile(pattern, flags=0)

[編輯 | 編輯原始碼]

編譯正則表達式。返回一個 re.Pattern 實例。re 模塊是通過該類型的實例方法來進行匹配操作的。

re.Pattern 的屬性
屬性 解釋
flags 旗標。是 compile 函數獲取的旗標以及正則表達式中用 (?imsxauL) 設置的匹配方式的組合。
groups 捕獲到的模式串中組的數量。
groupindex 映射由 (?P<name>) 定義的、有命名的組,其命名:索引位置組成的的字典。
如果沒有有命名的組,那字典就是空的。
pattern 編譯對象的原始樣式字符串。

re.Pattern 實例方法

[編輯 | 編輯原始碼]

簡單匹配

[編輯 | 編輯原始碼]
search(string[, pos[, endpos]])
[編輯 | 編輯原始碼]

string[pos: endpos] 中,查找匹配正則表達式的第一個位置,並返回對應的 re.Match 實例。如果沒有匹配的位置,則返回 None。

match(string[, pos[, endpos]])
[編輯 | 編輯原始碼]

類似 search 方法,但是從 string[pos: endpos] 的開頭開始匹配:不在 string[pos: endpos] 最開頭的、匹配的位置都不會被匹配到。

fullmatch(string[, pos[, endpos]])
[編輯 | 編輯原始碼]

如果 string[pos: endpos] 整個字符串都與正則表達式匹配,則返回相應的 re.Match 實例。

finditer(string[, pos[, endpos]])
[編輯 | 編輯原始碼]

string[pos: endpos] 中,查找匹配正則表達式的、所有非重複的位置。

每個位置,都會生成一個 re.Match 實例。該函數會返回生成的 re.Match 實例組成的迭代器。

findall(string[, pos[, endpos]])
[編輯 | 編輯原始碼]

類似 finditer 方法。但是輸出不同。

如果正則表達式中不包含一般的組,則會輸出匹配的子字符串組成的列表。而如果正則表達式中包含組,則只輸出組中的內容。比如:

import re
p = re.compile(r"\b[tT]\w+\b")
s1 = "This is a test string."
print(p.findall(s1)) #输出:['This', 'test']

q = re.compile(r"\b(\w+)=([^ ]+)")
s2 = '<img src="./image.png" width=100 height=100 />'
print(q.findall(s2)) #输出:[('src', '"./image.png"'), ('width', '100'), ('height', '100')]
split(string, maxsplit=0)
[編輯 | 編輯原始碼]

string 中所有匹配的子字符串為分割符,返回分割後的、子字符串的列表。

最多進行 maxsplit 次分割。

特別的:

  • 如果 string 的開頭被匹配,則返回的列表會以空字符串開頭。
  • 如果正則表達式中包含一般的組(而非(?:...)的組),則會在分割中保留組內匹配的內容。
import re
p = re.compile("(a)(b)")
q = re.compile("(?:a)(?:b)")

s = "ab"

print(p.split(s)) #输出:['c', 'a', 'b', 'c']
print(q.split(s)) #输出:['c', 'c']

可以看出,使用一般的組的 p 在進行分割時,輸出的結果中包含了組中的內容。而使用非捕獲模式的 q 則沒有進行這樣的操作。

sub(repl, string, count=0)
[編輯 | 編輯原始碼]

repl 所示的模式替換 string 中、匹配的內容。最多替換 count 次。repl 可以是字符串或函數。

如果 repl 是字符串,則直接進行替換,比如:

import re
p = re.compile(r"\b(\w+)=([^ ]+)")
s = '<img src="./image.png" width=100 height=100 />'
r = 'REPLACE'

print(p.sub(r, s))  #输出:<img REPLACE REPLACE REPLACE />

特別的, repl 中包含的、字符串轉義序列的原始序列都會被轉義。並且一些特殊的轉義也會被執行:

特殊轉義
轉義 註釋
\g<num> 正則表達式中,第 num 個組匹配到的內容
\num 正則表達式中,第 num 個組匹配到的內容
由於和 \ooo 衝突,num 不能超過 100,且
開頭不能為 0。
\g<name> 正則表達式中,名為 name 的組匹配到的內容
import re
p = re.compile(r"\b(?P<arg>\w+)=([^ ]+)")
s = '<img src="./image.png" />'
r = r'\g<1>\1\g<arg>'

print(p.sub(r, s))  #输出:<img srcsrcsrc />

如果 repl 是函數,則該函數應可以傳入每次匹配時,對應的 re.Match 實例,並返回替換的結果。

import re
p = re.compile(r"\b(\w+)=([^ ]+)")
s = '<img src="./image.png" width=100 height=100 />'
def r(matchobj):
    print(matchobj.string[matchobj.start():matchobj.end()])
    return "REPLACE"

print(p.sub(r, s))

輸出為:

src="./image.png"
width=100
height=100
<img REPLACE REPLACE REPLACE />
subn(repl, string, count=0)
[編輯 | 編輯原始碼]

類似 sub 方法,但返回一個元組: (替换后字符串, 替换次数)

單次使用

[編輯 | 編輯原始碼]

如果只匹配一次,也可以直接使用 re 模塊的以下函數:

函數 等同於
re.search(pattern, string, flags=0) re.compile(pattern, flags).search(string)
re.match(pattern, string, flags=0) re.compile(pattern, flags).match(string)
re.fullmatch(pattern, string, flags=0) re.compile(pattern, flags).fullmatch(string)
re.split(pattern, string, maxsplit=0, flags=0) re.compile(pattern, flags).split(string, maxsplit)
re.findall(pattern, string, flags=0) re.compile(pattern, flags).findall(string)
re.finditer(pattern, string, flags=0) re.compile(pattern, flags).finditer(string)
re.sub(pattern, repl, string, count=0, flags=0) re.compile(pattern, flags).sub(repl, string, count)
re.subn(pattern, repl, string, count=0, flags=0) re.compile(pattern, flags).subn(repl, string, count)

re.Match 的實例方法與屬性

[編輯 | 編輯原始碼]

替換字符串

[編輯 | 編輯原始碼]
expand(template)
[編輯 | 編輯原始碼]

替換字符串 template 的內容,使其被轉義。並返回替換後的字符串。

除字符串的轉義之外,\1\g<1> 等也會被轉義。

匹配到的組

[編輯 | 編輯原始碼]
group([group1, ...])
[編輯 | 編輯原始碼]

返回指定的組所匹配的內容。

其參數可以為正整數,代表組的索引(以 1 開頭)。也可以是字符串,代表組的名稱。

如果只有一個參數,則會返回字符串。如果有多個參數,則會返回字符串組成的元組。

特別的:

  • 參數 0 對應的是匹配的完整子字符串。
  • 不輸入任何參數時,等同於 self.group(0)
import re
p = re.compile(r"\b(?P<attr>\w+)=(?P<value>[^ ]+)")
s = '<img src="./image.png" width=100 height=100 />'
m = p.search(s)

print(m.group())               #输出:src="./image.png"
print(m.group(0))              #输出:src="./image.png"
print(m.group(1))              #输出:src
print(m.group(1,2))            #输出:('src', '"./image.png"')
print(m.group("attr","value")) #输出:('src', '"./image.png"')
__getitem__(g)
[編輯 | 編輯原始碼]

使用 self[g] 來調用此方法。

等同於 self.group(g)

groups(default=None)
[編輯 | 編輯原始碼]

返回包含所有匹配子組的字符串。對於總共有 n 個組的情況,等同於 self.group(1,2,...,n)

形如 (pattern)* 的組可能一次都不會被匹配。此時,該組對應的位置會輸出 default 的內容。

groupdict(default=None)
[編輯 | 編輯原始碼]

類似 groups 方法,但是返回的是 组的名称:匹配到的内容 的字典。

lastindex
[編輯 | 編輯原始碼]

該屬性保存最後一個匹配的整數索引值。如果沒有匹配的組,該屬性為 None。

嵌套中的組不會被計數。比如,對於字符串 'ab',表達式 (a)b, ((a)(b)), 和 ((ab)) 將得到 lastindex == 1 , 而 (a)(b) 會得到 lastindex == 2 。

lastgroup
[編輯 | 編輯原始碼]

最後一個匹配的命名組名字。如果沒有匹配的組,該屬性為 None。

start([group])
[編輯 | 編輯原始碼]

返回 group 所示的組,在原始字符串中起始位置的索引。

如果不輸入 groupgroup 為 0,則返回匹配開始的位置。

end([group])
[編輯 | 編輯原始碼]

返回 group 所示的組,在原始字符串中結束位置的索引。

如果不輸入 groupgroup 為 0,則返回匹配結束的位置。

span([group])
[編輯 | 編輯原始碼]

返回 (start([group]), end([group])) 元組。

匹配參數

[編輯 | 編輯原始碼]

生成 re.Match 需要用到 使用 re.compile(pattern).match(string, pos, endpos) 或 re.compile(pattern).search(string, pos, endpos) 等方法。以下屬性表示其中的參數或對象。

生成此 re.Match 實例所使用的參數 pos。

生成此 re.Match 實例所使用的參數 endpos。

生成此 re.Match 實例所使用的 re.Pattern 實例。

生成此 re.Match 實例所使用的參數 string。即被匹配的字符串。

其它操作

[編輯 | 編輯原始碼]

re.escape(pattern)

[編輯 | 編輯原始碼]

生成一個能匹配 pattern 字符串的、正則表達式字符串。

re.purge()

[編輯 | 編輯原始碼]

清除正則表達式的緩存。

注意事項

[編輯 | 編輯原始碼]

由於「多次匹配」的匹配機制,一些正則表達式可能會導致匹配時間隨字符串長度指數增長,比如以下是導致 Cloudflare 在 2019 年 7 月發生全球宕機事故的正則表達式的一部分:

  • .*(?:.*=.*)

如果用這個正則表達式來匹配形如 title=User:Xyy23330121 的內容,它會:

  • .* 匹配到 title=User:Xyy23330121
    • .* 匹配到空字符串
      • = 到字符串尾,無法匹配,回退
    • 空字符串無法回退,繼續向前回退。
  • .* 匹配到 title=User:Xyy2333012
    • .* 匹配到 1
      • = 到字符串尾,無法匹配,回退
    • .* 匹配到空字符串
      • = 匹配到 1,無法匹配,回退
    • 空字符串無法回退,繼續向前回退。
  • .* 匹配到 title=User:Xyy233301
  • ...

從結論而言,它會嘗試匹配總共 1 + 2 + ... + 16 = 136 次才會正確匹配所有內容。而如果等號後面的內容更多,情況只會更糟。

請在設置正則表達式時儘可能慎重。

參考文獻

[編輯 | 編輯原始碼]