re
--- 正則表達(dá)式操作?
Source code: Lib/re/
本模塊提供了與 Perl 語(yǔ)言類似的正則表達(dá)式匹配操作。
模式和被搜索的字符串既可以是 Unicode 字符串 (str
) ,也可以是8位字節(jié)串 (bytes
)。 但是,Unicode 字符串與 8 位字節(jié)串不能混用:也就是說(shuō),不能用字節(jié)串模式匹配 Unicode 字符串,反之亦然;同理,替換操作時(shí),替換字符串的類型也必須與所用的模式和搜索字符串的類型一致。
正則表達(dá)式用反斜杠字符 ('\'
) 表示特殊形式,或是允許在使用特殊字符時(shí),不引發(fā)它們的特殊含義。 這與 Python 的字符串字面值中對(duì)相同字符出于相同目的的用法產(chǎn)生沖突;例如,要匹配一個(gè)反斜杠字面值,用戶可能必須寫成 '\\\\'
來(lái)作為模式字符串,因?yàn)檎齽t表達(dá)式必須為 \\
,而每個(gè)反斜杠在普通 Python 字符串字面值中又必須表示為 \\
。 而且還要注意,在 Python 的字符串字面值中使用的反斜杠如果有任何無(wú)效的轉(zhuǎn)義序列,現(xiàn)在會(huì)觸發(fā) DeprecationWarning
,但以后會(huì)改為 SyntaxError
。 此行為即使對(duì)于正則表達(dá)式來(lái)說(shuō)有效的轉(zhuǎn)義字符同樣會(huì)發(fā)生。
解決辦法是對(duì)于正則表達(dá)式樣式使用 Python 的原始字符串表示法;在帶有 'r'
前綴的字符串字面值中,反斜杠不必做任何特殊處理。 因此 r"\n"
表示包含 '\'
和 'n'
兩個(gè)字符的字符串,而 "\n"
則表示只包含一個(gè)換行符的字符串。 樣式在 Python 代碼中通常都使用原始字符串表示法。
絕大多數(shù)正則表達(dá)式操作都提供為模塊函數(shù)和方法,在 編譯正則表達(dá)式. 這些函數(shù)是一個(gè)捷徑,不需要先編譯正則對(duì)象,但是損失了一些優(yōu)化參數(shù)。
正則表達(dá)式語(yǔ)法?
正則表達(dá)式(或 RE)指定了一組與之匹配的字符串;模塊內(nèi)的函數(shù)可以檢查某個(gè)字符串是否與給定的正則表達(dá)式匹配(或者正則表達(dá)式是否匹配到字符串,這兩種說(shuō)法含義相同)。
正則表達(dá)式可以拼接;如果 A 和 B 都是正則表達(dá)式,則 AB 也是正則表達(dá)式。通常,如果字符串 p 匹配 A,并且另一個(gè)字符串 q 匹配 B,那么 pq 可以匹配 AB。除非 A 或者 B 包含低優(yōu)先級(jí)操作,A 和 B 存在邊界條件;或者命名組引用。所以,復(fù)雜表達(dá)式可以很容易的從這里描述的簡(jiǎn)單源語(yǔ)表達(dá)式構(gòu)建。更多正則表達(dá)式理論和實(shí)現(xiàn),詳見(jiàn) the Friedl book [Frie09] ,或者其他構(gòu)建編譯器的書籍。
以下是正則表達(dá)式格式的簡(jiǎn)要說(shuō)明。更詳細(xì)的信息和演示,參考 正則表達(dá)式HOWTO。
正則表達(dá)式可以包含普通或者特殊字符。絕大部分普通字符,比如 'A'
, 'a'
, 或者 '0'
,都是最簡(jiǎn)單的正則表達(dá)式。它們就匹配自身。你可以拼接普通字符,所以 last
匹配字符串 'last'
. (在這一節(jié)的其他部分,我們將用 this special style
這種方式表示正則表達(dá)式,通常不帶引號(hào),要匹配的字符串用 'in single quotes'
,單引號(hào)形式。)
有些字符,比如 '|'
或者 '('
,屬于特殊字符。 特殊字符既可以表示它的普通含義, 也可以影響它旁邊的正則表達(dá)式的解釋。
Repetition operators or quantifiers (*
, +
, ?
, {m,n}
, etc) cannot be
directly nested. This avoids ambiguity with the non-greedy modifier suffix
?
, and with other modifiers in other implementations. To apply a second
repetition to an inner repetition, parentheses may be used. For example,
the expression (?:a{6})*
matches any multiple of six 'a'
characters.
特殊字符有:
.
(點(diǎn)) 在默認(rèn)模式,匹配除了換行的任意字符。如果指定了標(biāo)簽
DOTALL
,它將匹配包括換行符的任意字符。
^
(插入符號(hào)) 匹配字符串的開(kāi)頭, 并且在
MULTILINE
模式也匹配換行后的首個(gè)符號(hào)。
$
匹配字符串尾或者在字符串尾的換行符的前一個(gè)字符,在
MULTILINE
模式下也會(huì)匹配換行符之前的文本。foo
匹配 'foo' 和 'foobar',但正則表達(dá)式foo$
只匹配 'foo'。 更有趣的是,在'foo1\nfoo2\n'
中搜索foo.$
,通常匹配 'foo2',但在MULTILINE
模式下可以匹配到 'foo1';在'foo\n'
中搜索$
會(huì)找到兩個(gè)(空的)匹配:一個(gè)在換行符之前,一個(gè)在字符串的末尾。
*
對(duì)它前面的正則式匹配0到任意次重復(fù), 盡量多的匹配字符串。
ab*
會(huì)匹配'a'
,'ab'
,或者'a'
后面跟隨任意個(gè)'b'
。
+
對(duì)它前面的正則式匹配1到任意次重復(fù)。
ab+
會(huì)匹配'a'
后面跟隨1個(gè)以上到任意個(gè)'b'
,它不會(huì)匹配'a'
。
?
對(duì)它前面的正則式匹配0到1次重復(fù)。
ab?
會(huì)匹配'a'
或者'ab'
。
*?
,+?
,??
The
'*'
,'+'
, and'?'
quantifiers are all greedy; they match as much text as possible. Sometimes this behaviour isn't desired; if the RE<.*>
is matched against'<a> b <c>'
, it will match the entire string, and not just'<a>'
. Adding?
after the quantifier makes it perform the match in non-greedy or minimal fashion; as few characters as possible will be matched. Using the RE<.*?>
will match only'<a>'
.
*+
,++
,?+
Like the
'*'
,'+'
, and'?'
quantifiers, those where'+'
is appended also match as many times as possible. However, unlike the true greedy quantifiers, these do not allow back-tracking when the expression following it fails to match. These are known as possessive quantifiers. For example,a*a
will match'aaaa'
because thea*
will match all 4'a'
s, but, when the final'a'
is encountered, the expression is backtracked so that in the end thea*
ends up matching 3'a'
s total, and the fourth'a'
is matched by the final'a'
. However, whena*+a
is used to match'aaaa'
, thea*+
will match all 4'a'
, but when the final'a'
fails to find any more characters to match, the expression cannot be backtracked and will thus fail to match.x*+
,x++
andx?+
are equivalent to(?>x*)
,(?>x+)
and(?>x?)
correspondingly.3.11 新版功能.
{m}
對(duì)其之前的正則式指定匹配 m 個(gè)重復(fù);少于 m 的話就會(huì)導(dǎo)致匹配失敗。比如,
a{6}
將匹配6個(gè)'a'
, 但是不能是5個(gè)。{m,n}
對(duì)正則式進(jìn)行 m 到 n 次匹配,在 m 和 n 之間取盡量多。 比如,
a{3,5}
將匹配 3 到 5個(gè)'a'
。忽略 m 意為指定下界為0,忽略 n 指定上界為無(wú)限次。 比如a{4,}b
將匹配'aaaab'
或者1000個(gè)'a'
尾隨一個(gè)'b'
,但不能匹配'aaab'
。逗號(hào)不能省略,否則無(wú)法辨別修飾符應(yīng)該忽略哪個(gè)邊界。{m,n}?
Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as few repetitions as possible. This is the non-greedy version of the previous quantifier. For example, on the 6-character string
'aaaaaa'
,a{3,5}
will match 5'a'
characters, whilea{3,5}?
will only match 3 characters.{m,n}+
Causes the resulting RE to match from m to n repetitions of the preceding RE, attempting to match as many repetitions as possible without establishing any backtracking points. This is the possessive version of the quantifier above. For example, on the 6-character string
'aaaaaa'
,a{3,5}+aa
attempt to match 5'a'
characters, then, requiring 2 more'a'
s, will need more characters than available and thus fail, whilea{3,5}aa
will match witha{3,5}
capturing 5, then 4'a'
s by backtracking and then the final 2'a'
s are matched by the finalaa
in the pattern.x{m,n}+
is equivalent to(?>x{m,n})
.3.11 新版功能.
\
轉(zhuǎn)義特殊字符(允許你匹配
'*'
,'?'
, 或者此類其他),或者表示一個(gè)特殊序列;特殊序列之后進(jìn)行討論。如果你沒(méi)有使用原始字符串(
r'raw'
)來(lái)表達(dá)樣式,要牢記Python也使用反斜杠作為轉(zhuǎn)義序列;如果轉(zhuǎn)義序列不被Python的分析器識(shí)別,反斜杠和字符才能出現(xiàn)在字符串中。如果Python可以識(shí)別這個(gè)序列,那么反斜杠就應(yīng)該重復(fù)兩次。這將導(dǎo)致理解障礙,所以高度推薦,就算是最簡(jiǎn)單的表達(dá)式,也要使用原始字符串。
[]
用于表示一個(gè)字符集合。在一個(gè)集合中:
字符可以單獨(dú)列出,比如
[amk]
匹配'a'
,'m'
, 或者'k'
。
可以表示字符范圍,通過(guò)用
'-'
將兩個(gè)字符連起來(lái)。比如[a-z]
將匹配任何小寫ASCII字符,[0-5][0-9]
將匹配從00
到59
的兩位數(shù)字,[0-9A-Fa-f]
將匹配任何十六進(jìn)制數(shù)位。 如果-
進(jìn)行了轉(zhuǎn)義 (比如[a\-z]
)或者它的位置在首位或者末尾(如[-a]
或[a-]
),它就只表示普通字符'-'
。特殊字符在集合中,失去它的特殊含義。比如
[(+*)]
只會(huì)匹配這幾個(gè)文法字符'('
,'+'
,'*'
, or')'
。
不在集合范圍內(nèi)的字符可以通過(guò) 取反 來(lái)進(jìn)行匹配。如果集合首字符是
'^'
,所有 不 在集合內(nèi)的字符將會(huì)被匹配,比如[^5]
將匹配所有字符,除了'5'
,[^^]
將匹配所有字符,除了'^'
.^
如果不在集合首位,就沒(méi)有特殊含義。在集合內(nèi)要匹配一個(gè)字符
']'
,有兩種方法,要么就在它之前加上反斜杠,要么就把它放到集合首位。比如,[()[\]{}]
和[]()[{}]
都可以匹配括號(hào)。
Unicode Technical Standard #18 里的嵌套集合和集合操作支持可能在未來(lái)添加。這將會(huì)改變語(yǔ)法,所以為了幫助這個(gè)改變,一個(gè)
FutureWarning
將會(huì)在有多義的情況里被raise
,包含以下幾種情況,集合由'['
開(kāi)始,或者包含下列字符序列'--'
,'&&'
,'~~'
, 和'||'
。為了避免警告,需要將它們用反斜杠轉(zhuǎn)義。
在 3.7 版更改: 如果一個(gè)字符串構(gòu)建的語(yǔ)義在未來(lái)會(huì)改變的話,一個(gè)
FutureWarning
會(huì)raise
。
|
A|B
, A 和 B 可以是任意正則表達(dá)式,創(chuàng)建一個(gè)正則表達(dá)式,匹配 A 或者 B. 任意個(gè)正則表達(dá)式可以用'|'
連接。它也可以在組合(見(jiàn)下列)內(nèi)使用。掃描目標(biāo)字符串時(shí),'|'
分隔開(kāi)的正則樣式從左到右進(jìn)行匹配。當(dāng)一個(gè)樣式完全匹配時(shí),這個(gè)分支就被接受。意思就是,一旦 A 匹配成功, B 就不再進(jìn)行匹配,即便它能產(chǎn)生一個(gè)更好的匹配?;蛘哒f(shuō),'|'
操作符絕不貪婪。 如果要匹配'|'
字符,使用\|
, 或者把它包含在字符集里,比如[|]
.
(...)
(組合),匹配括號(hào)內(nèi)的任意正則表達(dá)式,并標(biāo)識(shí)出組合的開(kāi)始和結(jié)尾。匹配完成后,組合的內(nèi)容可以被獲取,并可以在之后用
\number
轉(zhuǎn)義序列進(jìn)行再次匹配,之后進(jìn)行詳細(xì)說(shuō)明。要匹配字符'('
或者')'
, 用\(
或\)
, 或者把它們包含在字符集合里:[(]
,[)]
.
(?…)
這是個(gè)擴(kuò)展標(biāo)記法 (一個(gè)
'?'
跟隨'('
并無(wú)含義)。'?'
后面的第一個(gè)字符決定了這個(gè)構(gòu)建采用什么樣的語(yǔ)法。這種擴(kuò)展通常并不創(chuàng)建新的組合;(?P<name>...)
是唯一的例外。 以下是目前支持的擴(kuò)展。(?aiLmsux)
(
'a'
,'i'
,'L'
,'m'
,'s'
,'u'
,'x'
中的一個(gè)或多個(gè)) 這個(gè)組合匹配一個(gè)空字符串;這些字符對(duì)正則表達(dá)式設(shè)置以下標(biāo)記re.A
(只匹配ASCII字符),re.I
(忽略大小寫),re.L
(語(yǔ)言依賴),re.M
(多行模式),re.S
(點(diǎn)dot匹配全部字符),re.U
(Unicode匹配), andre.X
(冗長(zhǎng)模式)。 (這些標(biāo)記在 模塊內(nèi)容 中描述) 如果你想將這些標(biāo)記包含在正則表達(dá)式中,這個(gè)方法就很有用,免去了在re.compile()
中傳遞 flag 參數(shù)。標(biāo)記應(yīng)該在表達(dá)式字符串首位表示。在 3.11 版更改: This construction can only be used at the start of the expression.
(?:…)
正則括號(hào)的非捕獲版本。 匹配在括號(hào)內(nèi)的任何正則表達(dá)式,但該分組所匹配的子字符串 不能 在執(zhí)行匹配后被獲取或是之后在模式中被引用。
(?aiLmsux-imsx:…)
(
'a'
,'i'
,'L'
,'m'
,'s'
,'u'
,'x'
中的0或者多個(gè), 之后可選跟隨'-'
在后面跟隨'i'
,'m'
,'s'
,'x'
中的一到多個(gè) .) 這些字符為表達(dá)式的其中一部分 設(shè)置 或者 去除 相應(yīng)標(biāo)記re.A
(只匹配ASCII),re.I
(忽略大小寫),re.L
(語(yǔ)言依賴),re.M
(多行),re.S
(點(diǎn)匹配所有字符),re.U
(Unicode匹配), andre.X
(冗長(zhǎng)模式)。(標(biāo)記描述在 模塊內(nèi)容 .)'a'
,'L'
and'u'
作為內(nèi)聯(lián)標(biāo)記是相互排斥的, 所以它們不能結(jié)合在一起,或者跟隨'-'
。 當(dāng)他們中的某個(gè)出現(xiàn)在內(nèi)聯(lián)組中,它就覆蓋了括號(hào)組內(nèi)的匹配模式。在Unicode樣式中,(?a:...)
切換為 只匹配ASCII,(?u:...)
切換為Unicode匹配 (默認(rèn)). 在byte樣式中(?L:...)
切換為語(yǔ)言依賴模式,(?a:...)
切換為 只匹配ASCII (默認(rèn))。這種方式只覆蓋組合內(nèi)匹配,括號(hào)外的匹配模式不受影響。3.6 新版功能.
在 3.7 版更改: 符號(hào)
'a'
,'L'
和'u'
同樣可以用在一個(gè)組合內(nèi)。(?>...)
Attempts to match
...
as if it was a separate regular expression, and if successful, continues to match the rest of the pattern following it. If the subsequent pattern fails to match, the stack can only be unwound to a point before the(?>...)
because once exited, the expression, known as an atomic group, has thrown away all stack points within itself. Thus,(?>.*).
would never match anything because first the.*
would match all characters possible, then, having nothing left to match, the final.
would fail to match. Since there are no stack points saved in the Atomic Group, and there is no stack point before it, the entire expression would thus fail to match.3.11 新版功能.
(?P<name>…)
Similar to regular parentheses, but the substring matched by the group is accessible via the symbolic group name name. Group names must be valid Python identifiers, and in bytes patterns they must contain only characters in the ASCII range. Each group name must be defined only once within a regular expression. A symbolic group is also a numbered group, just as if the group were not named.
命名組合可以在三種上下文中引用。如果樣式是
(?P<quote>['"]).*?(?P=quote)
(也就是說(shuō),匹配單引號(hào)或者雙引號(hào)括起來(lái)的字符串):引用組合 "quote" 的上下文
引用方法
在正則式自身內(nèi)
(?P=quote)
(如示)\1
處理匹配對(duì)象 m
m.group('quote')
m.end('quote')
(等)
傳遞到
re.sub()
里的 repl 參數(shù)中\g<quote>
\g<1>
\1
在 3.12 版更改: In bytes patterns group names must contain only characters in the ASCII range.
(?P=name)
反向引用一個(gè)命名組合;它匹配前面那個(gè)叫 name 的命名組中匹配到的串同樣的字串。
(?#…)
注釋;里面的內(nèi)容會(huì)被忽略。
(?=…)
匹配
…
的內(nèi)容,但是并不消費(fèi)樣式的內(nèi)容。這個(gè)叫做 lookahead assertion。比如,Isaac (?=Asimov)
匹配'Isaac '
只有在后面是'Asimov'
的時(shí)候。
(?!…)
匹配
…
不符合的情況。這個(gè)叫 negative lookahead assertion (前視取反)。比如說(shuō),Isaac (?!Asimov)
只有后面 不 是'Asimov'
的時(shí)候才匹配'Isaac '
。
(?<=…)
匹配字符串的當(dāng)前位置,它的前面匹配
...
的內(nèi)容到當(dāng)前位置。這叫 positive lookbehind assertion (正向后視斷定)。(?<=abc)def
會(huì)在'abcdef'
中找到一個(gè)匹配,因?yàn)楹笠晻?huì)往后看3個(gè)字符并檢查是否包含匹配的樣式。包含的匹配樣式必須是定長(zhǎng)的,意思就是abc
或a|b
是允許的,但是a*
和a{3,4}
不可以。注意以 positive lookbehind assertions 開(kāi)始的樣式,如(?<=abc)def
,并不是從 a 開(kāi)始搜索,而是從 d 往回看的。你可能更加愿意使用search()
函數(shù),而不是match()
函數(shù):>>> import re >>> m = re.search('(?<=abc)def', 'abcdef') >>> m.group(0) 'def'
這個(gè)例子搜索一個(gè)跟隨在連字符后的單詞:
>>> m = re.search(r'(?<=-)\w+', 'spam-egg') >>> m.group(0) 'egg'
在 3.5 版更改: 添加定長(zhǎng)組合引用的支持。
(?<!…)
匹配當(dāng)前位置之前不是
...
的樣式。這個(gè)叫 negative lookbehind assertion (后視斷定取非)。類似正向后視斷定,包含的樣式匹配必須是定長(zhǎng)的。由 negative lookbehind assertion 開(kāi)始的樣式可以從字符串搜索開(kāi)始的位置進(jìn)行匹配。(?(id/name)yes-pattern|no-pattern)
如果給定的 id 或 name 存在,將會(huì)嘗試匹配
yes-pattern
,否則就嘗試匹配no-pattern
,no-pattern
可選,也可以被忽略。比如,(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)
是一個(gè)email樣式匹配,將匹配'<user@host.com>'
或'user@host.com'
,但不會(huì)匹配'<user@host.com'
,也不會(huì)匹配'user@host.com>'
。在 3.12 版更改: Group id can only contain ASCII digits.
由 '\'
和一個(gè)字符組成的特殊序列在以下列出。 如果普通字符不是ASCII數(shù)位或者ASCII字母,那么正則樣式將匹配第二個(gè)字符。比如,\$
匹配字符 '$'
.
\number
匹配數(shù)字代表的組合。每個(gè)括號(hào)是一個(gè)組合,組合從1開(kāi)始編號(hào)。比如
(.+) \1
匹配'the the'
或者'55 55'
, 但不會(huì)匹配'thethe'
(注意組合后面的空格)。這個(gè)特殊序列只能用于匹配前面99個(gè)組合。如果 number 的第一個(gè)數(shù)位是0, 或者 number 是三個(gè)八進(jìn)制數(shù),它將不會(huì)被看作是一個(gè)組合,而是八進(jìn)制的數(shù)字值。在'['
和']'
字符集合內(nèi),任何數(shù)字轉(zhuǎn)義都被看作是字符。
\A
只匹配字符串開(kāi)始。
\b
匹配空字符串,但只在單詞開(kāi)始或結(jié)尾的位置。一個(gè)單詞被定義為一個(gè)單詞字符的序列。注意,通常
\b
定義為\w
和\W
字符之間,或者\w
和字符串開(kāi)始/結(jié)尾的邊界, 意思就是r'\bfoo\b'
匹配'foo'
,'foo.'
,'(foo)'
,'bar foo baz'
但不匹配'foobar'
或者'foo3'
。默認(rèn)情況下,Unicode字母和數(shù)字是在Unicode樣式中使用的,但是可以用
ASCII
標(biāo)記來(lái)更改。如果LOCALE
標(biāo)記被設(shè)置的話,詞的邊界是由當(dāng)前語(yǔ)言區(qū)域設(shè)置決定的,\b
表示退格字符,以便與Python字符串文本兼容。
\B
匹配空字符串,但 不 能在詞的開(kāi)頭或者結(jié)尾。意思就是
r'py\B'
匹配'python'
,'py3'
,'py2'
, 但不匹配'py'
,'py.'
, 或者'py!'
.\B
是\b
的取非,所以Unicode樣式的詞語(yǔ)是由Unicode字母,數(shù)字或下劃線構(gòu)成的,雖然可以用ASCII
標(biāo)志來(lái)改變。如果使用了LOCALE
標(biāo)志,則詞的邊界由當(dāng)前語(yǔ)言區(qū)域設(shè)置。
\d
- 對(duì)于 Unicode (str) 樣式:
匹配任何Unicode十進(jìn)制數(shù)(就是在Unicode字符目錄[Nd]里的字符)。這包括了
[0-9]
,和很多其他的數(shù)字字符。如果設(shè)置了ASCII
標(biāo)志,就只匹配[0-9]
。- 對(duì)于8位(bytes)樣式:
匹配任何十進(jìn)制數(shù),就是
[0-9]
。
\D
匹配任何非十進(jìn)制數(shù)字的字符。就是
\d
取非。 如果設(shè)置了ASCII
標(biāo)志,就相當(dāng)于[^0-9]
。
\s
- 對(duì)于 Unicode (str) 樣式:
匹配任何Unicode空白字符(包括
[ \t\n\r\f\v]
,還有很多其他字符,比如不同語(yǔ)言排版規(guī)則約定的不換行空格)。如果ASCII
被設(shè)置,就只匹配[ \t\n\r\f\v]
。- 對(duì)于8位(bytes)樣式:
匹配ASCII中的空白字符,就是
[ \t\n\r\f\v]
。
\S
匹配任何非空白字符。就是
\s
取非。如果設(shè)置了ASCII
標(biāo)志,就相當(dāng)于[^ \t\n\r\f\v]
。
\w
\W
匹配非單詞字符的字符。這與
\w
正相反。如果使用了ASCII
旗標(biāo),這就等價(jià)于[^a-zA-Z0-9_]
。如果使用了LOCALE
旗標(biāo),則會(huì)匹配當(dāng)前區(qū)域中既非字母數(shù)字也非下劃線的字符。
\Z
只匹配字符串尾。
絕大部分Python的標(biāo)準(zhǔn)轉(zhuǎn)義字符也被正則表達(dá)式分析器支持。:
\a \b \f \n
\N \r \t \u
\U \v \x \\
(注意 \b
被用于表示詞語(yǔ)的邊界,它只在字符集合內(nèi)表示退格,比如 [\b]
。)
'\u'
, '\U'
和 '\N'
轉(zhuǎn)義序列只在 Unicode 模式中可被識(shí)別。 在 bytes 模式中它們會(huì)導(dǎo)致錯(cuò)誤。 未知的 ASCII 字母轉(zhuǎn)義序列保留在未來(lái)使用,會(huì)被當(dāng)作錯(cuò)誤來(lái)處理。
八進(jìn)制轉(zhuǎn)義包含為一個(gè)有限形式。如果首位數(shù)字是 0, 或者有三個(gè)八進(jìn)制數(shù)位,那么就認(rèn)為它是八進(jìn)制轉(zhuǎn)義。其他的情況,就看作是組引用。對(duì)于字符串文本,八進(jìn)制轉(zhuǎn)義最多有三個(gè)數(shù)位長(zhǎng)。
在 3.3 版更改: 增加了 '\u'
和 '\U'
轉(zhuǎn)義序列。
在 3.6 版更改: 由 '\'
和一個(gè)ASCII字符組成的未知轉(zhuǎn)義會(huì)被看成錯(cuò)誤。
在 3.8 版更改: 添加了 '\N{name}'
轉(zhuǎn)義序列。 與在字符串字面值中一樣,它擴(kuò)展了命名 Unicode 字符 (例如 '\N{EM DASH}'
)。
模塊內(nèi)容?
模塊定義了幾個(gè)函數(shù)、常量,和一個(gè)異常。有些函數(shù)是編譯后的正則表達(dá)式方法的簡(jiǎn)化版本(少了一些特性)。重要的應(yīng)用程序大多會(huì)在使用前先編譯正則表達(dá)式。
Flags?
在 3.6 版更改: 標(biāo)志常量現(xiàn)在是 RegexFlag
類的實(shí)例,這個(gè)類是 enum.IntFlag
的子類。
- class re.RegexFlag?
An
enum.IntFlag
class containing the regex options listed below.3.11 新版功能: - added to
__all__
- re.A?
- re.ASCII?
讓
\w
,\W
,\b
,\B
,\d
,\D
,\s
和\S
只匹配ASCII,而不是Unicode。這只對(duì)Unicode樣式有效,會(huì)被byte樣式忽略。相當(dāng)于前面語(yǔ)法中的內(nèi)聯(lián)標(biāo)志(?a)
。注意,為了保持向后兼容,
re.U
標(biāo)記依然存在(還有他的同義re.UNICODE
和嵌入形式(?u)
) , 但是這些在 Python 3 是冗余的,因?yàn)槟J(rèn)字符串已經(jīng)是Unicode了(并且Unicode匹配不允許byte出現(xiàn))。
- re.DEBUG?
顯示編譯時(shí)的debug信息,沒(méi)有內(nèi)聯(lián)標(biāo)記。
- re.I?
- re.IGNORECASE?
進(jìn)行忽略大小寫匹配;表達(dá)式如
[A-Z]
也會(huì)匹配小寫字符。Unicode匹配(比如ü
匹配ü
)同樣有用,除非設(shè)置了re.ASCII
標(biāo)記來(lái)禁用非ASCII匹配。當(dāng)前語(yǔ)言區(qū)域不會(huì)改變這個(gè)標(biāo)記,除非設(shè)置了re.LOCALE
標(biāo)記。這個(gè)相當(dāng)于內(nèi)聯(lián)標(biāo)記(?i)
。注意,當(dāng)設(shè)置了
IGNORECASE
標(biāo)記,搜索Unicode樣式[a-z]
或[A-Z]
的結(jié)合時(shí),它將會(huì)匹配52個(gè)ASCII字符和4個(gè)額外的非ASCII字符: '?' (U+0130, 拉丁大寫的 I 帶個(gè)點(diǎn)在上面), '?' (U+0131, 拉丁小寫沒(méi)有點(diǎn)的 I ), '?' (U+017F, 拉丁小寫長(zhǎng) s) and 'K' (U+212A, 開(kāi)爾文符號(hào)).如果使用ASCII
標(biāo)記,就只匹配 'a' 到 'z' 和 'A' 到 'Z' 。
- re.L?
- re.LOCALE?
由當(dāng)前語(yǔ)言區(qū)域決定
\w
,\W
,\b
,\B
和大小寫敏感匹配。這個(gè)標(biāo)記只能對(duì)byte樣式有效。這個(gè)標(biāo)記不推薦使用,因?yàn)檎Z(yǔ)言區(qū)域機(jī)制很不可靠,它一次只能處理一個(gè) "習(xí)慣”,而且只對(duì)8位字節(jié)有效。Unicode匹配在Python 3 里默認(rèn)啟用,并可以處理不同語(yǔ)言。 這個(gè)對(duì)應(yīng)內(nèi)聯(lián)標(biāo)記(?L)
。在 3.7 版更改: 設(shè)置了
re.LOCALE
標(biāo)記的編譯正則對(duì)象不再在編譯時(shí)依賴語(yǔ)言區(qū)域設(shè)置。語(yǔ)言區(qū)域設(shè)置只在匹配的時(shí)候影響其結(jié)果。
- re.M?
- re.MULTILINE?
設(shè)置以后,樣式字符
'^'
匹配字符串的開(kāi)始,和每一行的開(kāi)始(換行符后面緊跟的符號(hào));樣式字符'$'
匹配字符串尾,和每一行的結(jié)尾(換行符前面那個(gè)符號(hào))。默認(rèn)情況下,’^’
匹配字符串頭,'$'
匹配字符串尾。對(duì)應(yīng)內(nèi)聯(lián)標(biāo)記(?m)
。
- re.NOFLAG?
Indicates no flag being applied, the value is
0
. This flag may be used as a default value for a function keyword argument or as a base value that will be conditionally ORed with other flags. Example of use as a default value:def myfunc(text, flag=re.NOFLAG): return re.match(text, flag)
3.11 新版功能.
- re.S?
- re.DOTALL?
讓
'.'
特殊字符匹配任何字符,包括換行符;如果沒(méi)有這個(gè)標(biāo)記,'.'
就匹配 除了 換行符的其他任意字符。對(duì)應(yīng)內(nèi)聯(lián)標(biāo)記(?s)
。
- re.X?
- re.VERBOSE?
這個(gè)標(biāo)記允許你編寫更具可讀性更友好的正則表達(dá)式。通過(guò)分段和添加注釋。空白符號(hào)會(huì)被忽略,除非在一個(gè)字符集合當(dāng)中或者由反斜杠轉(zhuǎn)義,或者在
*?
,(?:
or(?P<…>
分組之內(nèi)。當(dāng)一個(gè)行內(nèi)有#
不在字符集和轉(zhuǎn)義序列,那么它之后的所有字符都是注釋。意思就是下面兩個(gè)正則表達(dá)式等價(jià)地匹配一個(gè)十進(jìn)制數(shù)字:
a = re.compile(r"""\d + # the integral part \. # the decimal point \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*")
對(duì)應(yīng)內(nèi)聯(lián)標(biāo)記
(?x)
。
Functions?
- re.compile(pattern, flags=0)?
將正則表達(dá)式的樣式編譯為一個(gè) 正則表達(dá)式對(duì)象 (正則對(duì)象),可以用于匹配,通過(guò)這個(gè)對(duì)象的方法
match()
,search()
以及其他如下描述。這個(gè)表達(dá)式的行為可以通過(guò)指定 標(biāo)記 的值來(lái)改變。值可以是以下任意變量,可以通過(guò)位的OR操作來(lái)結(jié)合(
|
操作符)。序列
prog = re.compile(pattern) result = prog.match(string)
等價(jià)于
result = re.match(pattern, string)
如果需要多次使用這個(gè)正則表達(dá)式的話,使用
re.compile()
和保存這個(gè)正則對(duì)象以便復(fù)用,可以讓程序更加高效。備注
通過(guò)
re.compile()
編譯后的樣式,和模塊級(jí)的函數(shù)會(huì)被緩存, 所以少數(shù)的正則表達(dá)式使用無(wú)需考慮編譯的問(wèn)題。
- re.search(pattern, string, flags=0)?
掃描整個(gè) 字符串 找到匹配樣式的第一個(gè)位置,并返回一個(gè)相應(yīng)的 匹配對(duì)象。如果沒(méi)有匹配,就返回一個(gè)
None
; 注意這和找到一個(gè)零長(zhǎng)度匹配是不同的。
- re.match(pattern, string, flags=0)?
如果 string 開(kāi)始的0或者多個(gè)字符匹配到了正則表達(dá)式樣式,就返回一個(gè)相應(yīng)的 匹配對(duì)象 。 如果沒(méi)有匹配,就返回
None
;注意它跟零長(zhǎng)度匹配是不同的。注意即便是
MULTILINE
多行模式,re.match()
也只匹配字符串的開(kāi)始位置,而不匹配每行開(kāi)始。如果你想定位 string 的任何位置,使用
search()
來(lái)替代(也可參考 search() vs. match() )
- re.fullmatch(pattern, string, flags=0)?
如果整個(gè) string 匹配到正則表達(dá)式樣式,就返回一個(gè)相應(yīng)的 匹配對(duì)象 。 否則就返回一個(gè)
None
;注意這跟零長(zhǎng)度匹配是不同的。3.4 新版功能.
- re.split(pattern, string, maxsplit=0, flags=0)?
用 pattern 分開(kāi) string 。 如果在 pattern 中捕獲到括號(hào),那么所有的組里的文字也會(huì)包含在列表里。如果 maxsplit 非零, 最多進(jìn)行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一個(gè)元素。
>>> re.split(r'\W+', 'Words, words, words.') ['Words', 'words', 'words', ''] >>> re.split(r'(\W+)', 'Words, words, words.') ['Words', ', ', 'words', ', ', 'words', '.', ''] >>> re.split(r'\W+', 'Words, words, words.', 1) ['Words', 'words, words.'] >>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE) ['0', '3', '9']
如果分隔符里有捕獲組合,并且匹配到字符串的開(kāi)始,那么結(jié)果將會(huì)以一個(gè)空字符串開(kāi)始。對(duì)于結(jié)尾也是一樣
>>> re.split(r'(\W+)', '...words, words...') ['', '...', 'words', ', ', 'words', '...', '']
這樣的話,分隔組將會(huì)出現(xiàn)在結(jié)果列表中同樣的位置。
樣式的空匹配僅在與前一個(gè)空匹配不相鄰時(shí)才會(huì)拆分字符串。
>>> re.split(r'\b', 'Words, words, words.') ['', 'Words', ', ', 'words', ', ', 'words', '.'] >>> re.split(r'\W*', '...words...') ['', '', 'w', 'o', 'r', 'd', 's', '', ''] >>> re.split(r'(\W*)', '...words...') ['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']
在 3.1 版更改: 增加了可選標(biāo)記參數(shù)。
在 3.7 版更改: 增加了空字符串的樣式分隔。
- re.findall(pattern, string, flags=0)?
Return all non-overlapping matches of pattern in string, as a list of strings or tuples. The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result.
The result depends on the number of capturing groups in the pattern. If there are no groups, return a list of strings matching the whole pattern. If there is exactly one group, return a list of strings matching that group. If multiple groups are present, return a list of tuples of strings matching the groups. Non-capturing groups do not affect the form of the result.
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest') ['foot', 'fell', 'fastest'] >>> re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10') [('width', '20'), ('height', '10')]
在 3.7 版更改: 非空匹配現(xiàn)在可以在前一個(gè)空匹配之后出現(xiàn)了。
- re.finditer(pattern, string, flags=0)?
pattern 在 string 里所有的非重復(fù)匹配,返回為一個(gè)迭代器 iterator 保存了 匹配對(duì)象 。 string 從左到右掃描,匹配按順序排列。空匹配也包含在結(jié)果里。
在 3.7 版更改: 非空匹配現(xiàn)在可以在前一個(gè)空匹配之后出現(xiàn)了。
- re.sub(pattern, repl, string, count=0, flags=0)?
返回通過(guò)使用 repl 替換在 string 最左邊非重疊出現(xiàn)的 pattern 而獲得的字符串。 如果樣式?jīng)]有找到,則不加改變地返回 string。 repl 可以是字符串或函數(shù);如為字符串,則其中任何反斜杠轉(zhuǎn)義序列都會(huì)被處理。 也就是說(shuō),
\n
會(huì)被轉(zhuǎn)換為一個(gè)換行符,\r
會(huì)被轉(zhuǎn)換為一個(gè)回車符,依此類推。 未知的 ASCII 字符轉(zhuǎn)義序列保留在未來(lái)使用,會(huì)被當(dāng)作錯(cuò)誤來(lái)處理。 其他未知轉(zhuǎn)義序列例如\&
會(huì)保持原樣。 向后引用像是\6
會(huì)用樣式中第 6 組所匹配到的子字符串來(lái)替換。 例如:>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', ... r'static PyObject*\npy_\1(void)\n{', ... 'def myfunc():') 'static PyObject*\npy_myfunc(void)\n{'
如果 repl 是一個(gè)函數(shù),那它會(huì)對(duì)每個(gè)非重復(fù)的 pattern 的情況調(diào)用。這個(gè)函數(shù)只能有一個(gè) 匹配對(duì)象 參數(shù),并返回一個(gè)替換后的字符串。比如
>>> def dashrepl(matchobj): ... if matchobj.group(0) == '-': return ' ' ... else: return '-' >>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 'pro--gram files' >>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE) 'Baked Beans & Spam'
樣式可以是一個(gè)字符串或者一個(gè) 樣式對(duì)象 。
可選參數(shù) count 是要替換的最大次數(shù);count 必須是非負(fù)整數(shù)。如果省略這個(gè)參數(shù)或設(shè)為 0,所有的匹配都會(huì)被替換。 樣式的空匹配僅在與前一個(gè)空匹配不相鄰時(shí)才會(huì)被替換,所以
sub('x*', '-', 'abxd')
返回'-a-b--d-'
。在字符串類型的 repl 參數(shù)里,如上所述的轉(zhuǎn)義和向后引用中,
\g<name>
會(huì)使用命名組合name
,(在(?P<name>…)
語(yǔ)法中定義)\g<number>
會(huì)使用數(shù)字組;\g<2>
就是\2
,但它避免了二義性,如\g<2>0
。\20
就會(huì)被解釋為組20,而不是組2后面跟隨一個(gè)字符'0'
。向后引用\g<0>
把 pattern 作為一整個(gè)組進(jìn)行引用。在 3.1 版更改: 增加了可選標(biāo)記參數(shù)。
在 3.5 版更改: 不匹配的組合替換為空字符串。
在 3.6 版更改: pattern 中的未知轉(zhuǎn)義(由
'\'
和一個(gè) ASCII 字符組成)被視為錯(cuò)誤。在 3.7 版更改: repl 中的未知轉(zhuǎn)義(由
'\'
和一個(gè) ASCII 字符組成)被視為錯(cuò)誤。在 3.7 版更改: 樣式中的空匹配相鄰接時(shí)會(huì)被替換。
在 3.12 版更改: Group id can only contain ASCII digits. In bytes replacement strings group names must contain only characters in the ASCII range.
- re.subn(pattern, repl, string, count=0, flags=0)?
行為與
sub()
相同,但是返回一個(gè)元組(字符串, 替換次數(shù))
.在 3.1 版更改: 增加了可選標(biāo)記參數(shù)。
在 3.5 版更改: 不匹配的組合替換為空字符串。
- re.escape(pattern)?
轉(zhuǎn)義 pattern 中的特殊字符。如果你想對(duì)任意可能包含正則表達(dá)式元字符的文本字符串進(jìn)行匹配,它就是有用的。比如
>>> print(re.escape('https://www.python.org')) https://www\.python\.org >>> legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:" >>> print('[%s]+' % re.escape(legal_chars)) [abcdefghijklmnopqrstuvwxyz0123456789!\#\$%\&'\*\+\-\.\^_`\|\~:]+ >>> operators = ['+', '-', '*', '/', '**'] >>> print('|'.join(map(re.escape, sorted(operators, reverse=True)))) /|\-|\+|\*\*|\*
這個(gè)函數(shù)不能被用于
sub()
和subn()
的替換字符串,只有反斜杠應(yīng)該被轉(zhuǎn)義。 例如:>>> digits_re = r'\d+' >>> sample = '/usr/sbin/sendmail - 0 errors, 12 warnings' >>> print(re.sub(digits_re, digits_re.replace('\\', r'\\'), sample)) /usr/sbin/sendmail - \d+ errors, \d+ warnings
在 3.3 版更改:
'_'
不再被轉(zhuǎn)義。在 3.7 版更改: 只有在正則表達(dá)式中具有特殊含義的字符才會(huì)被轉(zhuǎn)義。 因此,
'!'
,'"'
,'%'
,"'"
,','
,'/'
,':'
,';'
,'<'
,'='
,'>'
,'@'
和"`"
將不再會(huì)被轉(zhuǎn)義。
- re.purge()?
清除正則表達(dá)式的緩存。
Exceptions?
- exception re.error(msg, pattern=None, pos=None)?
當(dāng)傳遞給函數(shù)的正則表達(dá)式不合法(比如括號(hào)不匹配),或者在編譯或匹配過(guò)程中出現(xiàn)其他錯(cuò)誤時(shí),會(huì)引發(fā)異常。所給字符串不匹配所給模式不會(huì)引發(fā)異常。異常實(shí)例有以下附加屬性:
- msg?
未格式化的錯(cuò)誤消息。
- pattern?
正則表達(dá)式的模式串。
- pos?
編譯失敗的 pattern 的位置索引(可以是
None
)。
- lineno?
對(duì)應(yīng) pos (可以是
None
) 的行號(hào)。
- colno?
對(duì)應(yīng) pos (可以是
None
) 的列號(hào)。
在 3.5 版更改: 增加了額外的屬性。
正則表達(dá)式對(duì)象 (正則對(duì)象)?
編譯后的正則表達(dá)式對(duì)象支持以下方法和屬性:
- Pattern.search(string[, pos[, endpos]])?
掃描整個(gè) string 尋找第一個(gè)匹配的位置, 并返回一個(gè)相應(yīng)的 匹配對(duì)象。如果沒(méi)有匹配,就返回
None
;注意它和零長(zhǎng)度匹配是不同的。可選的第二個(gè)參數(shù) pos 給出了字符串中開(kāi)始搜索的位置索引;默認(rèn)為
0
,它不完全等價(jià)于字符串切片;'^'
樣式字符匹配字符串真正的開(kāi)頭,和換行符后面的第一個(gè)字符,但不會(huì)匹配索引規(guī)定開(kāi)始的位置。可選參數(shù) endpos 限定了字符串搜索的結(jié)束;它假定字符串長(zhǎng)度到 endpos , 所以只有從
pos
到endpos - 1
的字符會(huì)被匹配。如果 endpos 小于 pos,就不會(huì)有匹配產(chǎn)生;另外,如果 rx 是一個(gè)編譯后的正則對(duì)象,rx.search(string, 0, 50)
等價(jià)于rx.search(string[:50], 0)
。>>> pattern = re.compile("d") >>> pattern.search("dog") # Match at index 0 <re.Match object; span=(0, 1), match='d'> >>> pattern.search("dog", 1) # No match; search doesn't include the "d"
- Pattern.match(string[, pos[, endpos]])?
如果 string 的 開(kāi)始位置 能夠找到這個(gè)正則樣式的任意個(gè)匹配,就返回一個(gè)相應(yīng)的 匹配對(duì)象。如果不匹配,就返回
None
;注意它與零長(zhǎng)度匹配是不同的。可選參數(shù) pos 和 endpos 與
search()
含義相同。>>> pattern = re.compile("o") >>> pattern.match("dog") # No match as "o" is not at the start of "dog". >>> pattern.match("dog", 1) # Match as "o" is the 2nd character of "dog". <re.Match object; span=(1, 2), match='o'>
如果你想定位匹配在 string 中的位置,使用
search()
來(lái)替代(另參考 search() vs. match())。
- Pattern.fullmatch(string[, pos[, endpos]])?
如果整個(gè) string 匹配這個(gè)正則表達(dá)式,就返回一個(gè)相應(yīng)的 匹配對(duì)象 。 否則就返回
None
; 注意跟零長(zhǎng)度匹配是不同的。可選參數(shù) pos 和 endpos 與
search()
含義相同。>>> pattern = re.compile("o[gh]") >>> pattern.fullmatch("dog") # No match as "o" is not at the start of "dog". >>> pattern.fullmatch("ogre") # No match as not the full string matches. >>> pattern.fullmatch("doggie", 1, 3) # Matches within given limits. <re.Match object; span=(1, 3), match='og'>
3.4 新版功能.
- Pattern.findall(string[, pos[, endpos]])?
類似函數(shù)
findall()
, 使用了編譯后樣式,但也可以接收可選參數(shù) pos 和 endpos ,限制搜索范圍,就像search()
。
- Pattern.finditer(string[, pos[, endpos]])?
類似函數(shù)
finditer()
, 使用了編譯后樣式,但也可以接收可選參數(shù) pos 和 endpos ,限制搜索范圍,就像search()
。
- Pattern.flags?
正則匹配標(biāo)記。這是可以傳遞給
compile()
的參數(shù),任何(?…)
內(nèi)聯(lián)標(biāo)記,隱性標(biāo)記比如UNICODE
的結(jié)合。
- Pattern.groups?
捕獲到的模式串中組的數(shù)量。
- Pattern.groupindex?
映射由
(?P<id>)
定義的命名符號(hào)組合和數(shù)字組合的字典。如果沒(méi)有符號(hào)組,那字典就是空的。
- Pattern.pattern?
編譯對(duì)象的原始樣式字符串。
在 3.7 版更改: 添加 copy.copy()
和 copy.deepcopy()
函數(shù)的支持。編譯后的正則表達(dá)式對(duì)象被認(rèn)為是原子性的。
匹配對(duì)象?
匹配對(duì)象總是有一個(gè)布爾值 True
。如果沒(méi)有匹配的話 match()
和 search()
返回 None
所以你可以簡(jiǎn)單的用 if
語(yǔ)句來(lái)判斷是否匹配
match = re.search(pattern, string)
if match:
process(match)
匹配對(duì)象支持以下方法和屬性:
- Match.expand(template)?
對(duì) template 進(jìn)行反斜杠轉(zhuǎn)義替換并且返回,就像
sub()
方法中一樣。轉(zhuǎn)義如同\n
被轉(zhuǎn)換成合適的字符,數(shù)字引用(\1
,\2
)和命名組合(\g<1>
,\g<name>
) 替換為相應(yīng)組合的內(nèi)容。在 3.5 版更改: 不匹配的組合替換為空字符串。
- Match.group([group1, ...])?
返回一個(gè)或者多個(gè)匹配的子組。如果只有一個(gè)參數(shù),結(jié)果就是一個(gè)字符串,如果有多個(gè)參數(shù),結(jié)果就是一個(gè)元組(每個(gè)參數(shù)對(duì)應(yīng)一個(gè)項(xiàng)),如果沒(méi)有參數(shù),組1默認(rèn)到0(整個(gè)匹配都被返回)。 如果一個(gè)組N 參數(shù)值為 0,相應(yīng)的返回值就是整個(gè)匹配字符串;如果它是一個(gè)范圍 [1..99],結(jié)果就是相應(yīng)的括號(hào)組字符串。如果一個(gè)組號(hào)是負(fù)數(shù),或者大于樣式中定義的組數(shù),就引發(fā)一個(gè)
IndexError
異常。如果一個(gè)組包含在樣式的一部分,并被匹配多次,就返回最后一個(gè)匹配。:>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist") >>> m.group(0) # The entire match 'Isaac Newton' >>> m.group(1) # The first parenthesized subgroup. 'Isaac' >>> m.group(2) # The second parenthesized subgroup. 'Newton' >>> m.group(1, 2) # Multiple arguments give us a tuple. ('Isaac', 'Newton')
如果正則表達(dá)式使用了
(?P<name>...)
語(yǔ)法, groupN 參數(shù)就也可能是命名組合的名字。如果一個(gè)字符串參數(shù)在樣式中未定義為組合名,就引發(fā)一個(gè)IndexError
異常。一個(gè)相對(duì)復(fù)雜的例子
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds") >>> m.group('first_name') 'Malcolm' >>> m.group('last_name') 'Reynolds'
命名組合同樣可以通過(guò)索引值引用
>>> m.group(1) 'Malcolm' >>> m.group(2) 'Reynolds'
如果一個(gè)組匹配成功多次,就只返回最后一個(gè)匹配
>>> m = re.match(r"(..)+", "a1b2c3") # Matches 3 times. >>> m.group(1) # Returns only the last match. 'c3'
- Match.__getitem__(g)?
這個(gè)等價(jià)于
m.group(g)
。這允許更方便的引用一個(gè)匹配>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist") >>> m[0] # The entire match 'Isaac Newton' >>> m[1] # The first parenthesized subgroup. 'Isaac' >>> m[2] # The second parenthesized subgroup. 'Newton'
3.6 新版功能.
- Match.groups(default=None)?
返回一個(gè)元組,包含所有匹配的子組,在樣式中出現(xiàn)的從1到任意多的組合。 default 參數(shù)用于不參與匹配的情況,默認(rèn)為
None
。例如:
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632") >>> m.groups() ('24', '1632')
如果我們使小數(shù)點(diǎn)可選,那么不是所有的組都會(huì)參與到匹配當(dāng)中。這些組合默認(rèn)會(huì)返回一個(gè)
None
,除非指定了 default 參數(shù)。>>> m = re.match(r"(\d+)\.?(\d+)?", "24") >>> m.groups() # Second group defaults to None. ('24', None) >>> m.groups('0') # Now, the second group defaults to '0'. ('24', '0')
- Match.groupdict(default=None)?
返回一個(gè)字典,包含了所有的 命名 子組。key就是組名。 default 參數(shù)用于不參與匹配的組合;默認(rèn)為
None
。 例如>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds") >>> m.groupdict() {'first_name': 'Malcolm', 'last_name': 'Reynolds'}
- Match.start([group])?
- Match.end([group])?
返回 group 匹配到的字串的開(kāi)始和結(jié)束標(biāo)號(hào)。group 默認(rèn)為0(意思是整個(gè)匹配的子串)。如果 group 存在,但未產(chǎn)生匹配,就返回
-1
。對(duì)于一個(gè)匹配對(duì)象 m, 和一個(gè)未參與匹配的組 g ,組 g (等價(jià)于m.group(g)
)產(chǎn)生的匹配是m.string[m.start(g):m.end(g)]
注意
m.start(group)
將會(huì)等于m.end(group)
,如果 group 匹配一個(gè)空字符串的話。比如,在m = re.search('b(c?)', 'cba')
之后,m.start(0)
為 1,m.end(0)
為 2,m.start(1)
和m.end(1)
都是 2,m.start(2)
引發(fā)一個(gè)IndexError
異常。這個(gè)例子會(huì)從email地址中移除掉 remove_this
>>> email = "tony@tiremove_thisger.net" >>> m = re.search("remove_this", email) >>> email[:m.start()] + email[m.end():] 'tony@tiger.net'
- Match.span([group])?
對(duì)于一個(gè)匹配 m , 返回一個(gè)二元組
(m.start(group), m.end(group))
。 注意如果 group 沒(méi)有在這個(gè)匹配中,就返回(-1, -1)
。group 默認(rèn)為0,就是整個(gè)匹配。
- Match.pos?
pos 的值,會(huì)傳遞給
search()
或match()
的方法 a 正則對(duì)象 。這個(gè)是正則引擎開(kāi)始在字符串搜索一個(gè)匹配的索引位置。
- Match.endpos?
endpos 的值,會(huì)傳遞給
search()
或match()
的方法 a 正則對(duì)象 。這個(gè)是正則引擎停止在字符串搜索一個(gè)匹配的索引位置。
- Match.lastindex?
捕獲組的最后一個(gè)匹配的整數(shù)索引值,或者
None
如果沒(méi)有匹配產(chǎn)生的話。比如,對(duì)于字符串'ab'
,表達(dá)式(a)b
,((a)(b))
, 和((ab))
將得到lastindex == 1
, 而(a)(b)
會(huì)得到lastindex == 2
。
- Match.lastgroup?
最后一個(gè)匹配的命名組名字,或者
None
如果沒(méi)有產(chǎn)生匹配的話。
- Match.re?
返回產(chǎn)生這個(gè)實(shí)例的 正則對(duì)象 , 這個(gè)實(shí)例是由 正則對(duì)象的
match()
或search()
方法產(chǎn)生的。
在 3.7 版更改: 添加了對(duì) copy.copy()
和 copy.deepcopy()
的支持。匹配對(duì)象被看作是原子性的。
正則表達(dá)式例子?
檢查對(duì)子?
在這個(gè)例子里,我們使用以下輔助函數(shù)來(lái)更好地顯示匹配對(duì)象:
def displaymatch(match):
if match is None:
return None
return '<Match: %r, groups=%r>' % (match.group(), match.groups())
假設(shè)你在寫一個(gè)撲克程序,一個(gè)玩家的一手牌為五個(gè)字符的串,每個(gè)字符表示一張牌,"a" 就是 A, "k" K, "q" Q, "j" J, "t" 為 10, "2" 到 "9" 表示2 到 9。
要看給定的字符串是否有效,我們可以按照以下步驟
>>> valid = re.compile(r"^[a2-9tjqk]{5}$")
>>> displaymatch(valid.match("akt5q")) # Valid.
"<Match: 'akt5q', groups=()>"
>>> displaymatch(valid.match("akt5e")) # Invalid.
>>> displaymatch(valid.match("akt")) # Invalid.
>>> displaymatch(valid.match("727ak")) # Valid.
"<Match: '727ak', groups=()>"
最后一手牌,"727ak"
,包含了一個(gè)對(duì)子,或者兩張同樣數(shù)值的牌。要用正則表達(dá)式匹配它,應(yīng)該使用向后引用如下
>>> pair = re.compile(r".*(.).*\1")
>>> displaymatch(pair.match("717ak")) # Pair of 7s.
"<Match: '717', groups=('7',)>"
>>> displaymatch(pair.match("718ak")) # No pairs.
>>> displaymatch(pair.match("354aa")) # Pair of aces.
"<Match: '354aa', groups=('a',)>"
要找出對(duì)子由什么牌組成,開(kāi)發(fā)者可以按照下面的方式來(lái)使用匹配對(duì)象的 group()
方法:
>>> pair = re.compile(r".*(.).*\1")
>>> pair.match("717ak").group(1)
'7'
# Error because re.match() returns None, which doesn't have a group() method:
>>> pair.match("718ak").group(1)
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
re.match(r".*(.).*\1", "718ak").group(1)
AttributeError: 'NoneType' object has no attribute 'group'
>>> pair.match("354aa").group(1)
'a'
模擬 scanf()?
Python 目前沒(méi)有一個(gè)類似c函數(shù) scanf()
的替代品。正則表達(dá)式通常比 scanf()
格式字符串要更強(qiáng)大一些,但也帶來(lái)更多復(fù)雜性。下面的表格提供了 scanf()
格式符和正則表達(dá)式大致相同的映射。
|
正則表達(dá)式 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
從文件名和數(shù)字提取字符串
/usr/sbin/sendmail - 0 errors, 4 warnings
你可以使用 scanf()
格式化
%s - %d errors, %d warnings
等價(jià)的正則表達(dá)式是:
(\S+) - (\d+) errors, (\d+) warnings
search() vs. match()?
Python 提供了兩種不同的操作:基于 re.match()
檢查字符串開(kāi)頭,或者 re.search()
檢查字符串的任意位置(默認(rèn)Perl中的行為)。
例如:
>>> re.match("c", "abcdef") # No match
>>> re.search("c", "abcdef") # Match
<re.Match object; span=(2, 3), match='c'>
在 search()
中,可以用 '^'
作為開(kāi)始來(lái)限制匹配到字符串的首位
>>> re.match("c", "abcdef") # No match
>>> re.search("^c", "abcdef") # No match
>>> re.search("^a", "abcdef") # Match
<re.Match object; span=(0, 1), match='a'>
注意 MULTILINE
多行模式中函數(shù) match()
只匹配字符串的開(kāi)始,但使用 search()
和以 '^'
開(kāi)始的正則表達(dá)式會(huì)匹配每行的開(kāi)始
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
<re.Match object; span=(4, 5), match='X'>
制作一個(gè)電話本?
split()
將字符串用參數(shù)傳遞的樣式分隔開(kāi)。這個(gè)方法對(duì)于轉(zhuǎn)換文本數(shù)據(jù)到易讀而且容易修改的數(shù)據(jù)結(jié)構(gòu),是很有用的,如下面的例子證明。
首先,這里是輸入。 它通常來(lái)自一個(gè)文件,這里我們使用三重引號(hào)字符串語(yǔ)法
>>> text = """Ross McFluff: 834.345.1254 155 Elm Street
...
... Ronald Heathmore: 892.345.3428 436 Finley Avenue
... Frank Burger: 925.541.7625 662 South Dogwood Way
...
...
... Heather Albrecht: 548.326.4584 919 Park Place"""
條目用一個(gè)或者多個(gè)換行符分開(kāi)。現(xiàn)在我們將字符串轉(zhuǎn)換為一個(gè)列表,每個(gè)非空行都有一個(gè)條目:
>>> entries = re.split("\n+", text)
>>> entries
['Ross McFluff: 834.345.1254 155 Elm Street',
'Ronald Heathmore: 892.345.3428 436 Finley Avenue',
'Frank Burger: 925.541.7625 662 South Dogwood Way',
'Heather Albrecht: 548.326.4584 919 Park Place']
最終,將每個(gè)條目分割為一個(gè)由名字、姓氏、電話號(hào)碼和地址組成的列表。我們?yōu)?split()
使用了 maxsplit
形參,因?yàn)榈刂分邪斜晃覀冏鳛榉指钅J降目崭穹?
>>> [re.split(":? ", entry, 3) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155 Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436 Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662 South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919 Park Place']]
:?
樣式匹配姓后面的冒號(hào),因此它不出現(xiàn)在結(jié)果列表中。如果 maxsplit
設(shè)置為 4
,我們還可以從地址中獲取到房間號(hào):
>>> [re.split(":? ", entry, 4) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155', 'Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436', 'Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662', 'South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919', 'Park Place']]
文字整理?
sub()
替換字符串中出現(xiàn)的樣式的每一個(gè)實(shí)例。這個(gè)例子證明了使用 sub()
來(lái)整理文字,或者隨機(jī)化每個(gè)字符的位置,除了首位和末尾字符
>>> def repl(m):
... inner_word = list(m.group(2))
... random.shuffle(inner_word)
... return m.group(1) + "".join(inner_word) + m.group(3)
>>> text = "Professor Abdolmalek, please report your absences promptly."
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Poefsrosr Aealmlobdk, pslaee reorpt your abnseces plmrptoy.'
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Pofsroser Aodlambelk, plasee reoprt yuor asnebces potlmrpy.'
查找所有副詞?
findall()
匹配樣式 所有 的出現(xiàn),不僅是像 search()
中的第一個(gè)匹配。比如,如果一個(gè)作者希望找到文字中的所有副詞,他可能會(huì)按照以下方法用 findall()
>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly\b", text)
['carefully', 'quickly']
查找所有的副詞及其位置?
如果需要匹配樣式的更多信息, finditer()
可以起到作用,它提供了 匹配對(duì)象 作為返回值,而不是字符串。繼續(xù)上面的例子,如果一個(gè)作者希望找到所有副詞和它的位置,可以按照下面方法使用 finditer()
>>> text = "He was carefully disguised but captured quickly by police."
>>> for m in re.finditer(r"\w+ly\b", text):
... print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0)))
07-16: carefully
40-47: quickly
原始字符串標(biāo)記?
原始字符串記法 (r"text"
) 保持正則表達(dá)式正常。否則,每個(gè)正則式里的反斜杠('\'
) 都必須前綴一個(gè)反斜杠來(lái)轉(zhuǎn)義。比如,下面兩行代碼功能就是完全一致的
>>> re.match(r"\W(.)\1\W", " ff ")
<re.Match object; span=(0, 4), match=' ff '>
>>> re.match("\\W(.)\\1\\W", " ff ")
<re.Match object; span=(0, 4), match=' ff '>
當(dāng)需要匹配一個(gè)字符反斜杠,它必須在正則表達(dá)式中轉(zhuǎn)義。在原始字符串記法,就是 r"\\"
。否則就必須用 "\\\\"
,來(lái)表示同樣的意思
>>> re.match(r"\\", r"\\")
<re.Match object; span=(0, 1), match='\\'>
>>> re.match("\\\\", r"\\")
<re.Match object; span=(0, 1), match='\\'>
寫一個(gè)詞法分析器?
一個(gè) 詞法器或詞法分析器 分析字符串,并分類成目錄組。 這是寫一個(gè)編譯器或解釋器的第一步。
文字目錄是由正則表達(dá)式指定的。這個(gè)技術(shù)是通過(guò)將這些樣式合并為一個(gè)主正則式,并且循環(huán)匹配來(lái)實(shí)現(xiàn)的
from typing import NamedTuple
import re
class Token(NamedTuple):
type: str
value: str
line: int
column: int
def tokenize(code):
keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
token_specification = [
('NUMBER', r'\d+(\.\d*)?'), # Integer or decimal number
('ASSIGN', r':='), # Assignment operator
('END', r';'), # Statement terminator
('ID', r'[A-Za-z]+'), # Identifiers
('OP', r'[+\-*/]'), # Arithmetic operators
('NEWLINE', r'\n'), # Line endings
('SKIP', r'[ \t]+'), # Skip over spaces and tabs
('MISMATCH', r'.'), # Any other character
]
tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
line_num = 1
line_start = 0
for mo in re.finditer(tok_regex, code):
kind = mo.lastgroup
value = mo.group()
column = mo.start() - line_start
if kind == 'NUMBER':
value = float(value) if '.' in value else int(value)
elif kind == 'ID' and value in keywords:
kind = value
elif kind == 'NEWLINE':
line_start = mo.end()
line_num += 1
continue
elif kind == 'SKIP':
continue
elif kind == 'MISMATCH':
raise RuntimeError(f'{value!r} unexpected on line {line_num}')
yield Token(kind, value, line_num, column)
statements = '''
IF quantity THEN
total := total + price * quantity;
tax := price * 0.05;
ENDIF;
'''
for token in tokenize(statements):
print(token)
該詞法器產(chǎn)生以下的輸出
Token(type='IF', value='IF', line=2, column=4)
Token(type='ID', value='quantity', line=2, column=7)
Token(type='THEN', value='THEN', line=2, column=16)
Token(type='ID', value='total', line=3, column=8)
Token(type='ASSIGN', value=':=', line=3, column=14)
Token(type='ID', value='total', line=3, column=17)
Token(type='OP', value='+', line=3, column=23)
Token(type='ID', value='price', line=3, column=25)
Token(type='OP', value='*', line=3, column=31)
Token(type='ID', value='quantity', line=3, column=33)
Token(type='END', value=';', line=3, column=41)
Token(type='ID', value='tax', line=4, column=8)
Token(type='ASSIGN', value=':=', line=4, column=12)
Token(type='ID', value='price', line=4, column=15)
Token(type='OP', value='*', line=4, column=21)
Token(type='NUMBER', value=0.05, line=4, column=23)
Token(type='END', value=';', line=4, column=27)
Token(type='ENDIF', value='ENDIF', line=5, column=4)
Token(type='END', value=';', line=5, column=9)
- Frie09
Friedl, Jeffrey. Mastering Regular Expressions. 3rd ed., O'Reilly Media, 2009. 該書的第三版不再包含 Python,但第一版極詳細(xì)地覆蓋了正則表達(dá)式模式串的編寫。