re --- 正則表達(dá)式操作?

Source code: Lib/re/


本模塊提供了與 Perl 語言類似的正則表達(dá)式匹配操作。

模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字節(jié)串 (bytes)。 但是,Unicode 字符串與 8 位字節(jié)串不能混用:也就是說,不能用字節(jié)串模式匹配 Unicode 字符串,反之亦然;同理,替換操作時,替換字符串的類型也必須與所用的模式和搜索字符串的類型一致。

正則表達(dá)式用反斜杠字符 ('\') 表示特殊形式,或是允許在使用特殊字符時,不引發(fā)它們的特殊含義。 這與 Python 的字符串字面值中對相同字符出于相同目的的用法產(chǎn)生沖突;例如,要匹配一個反斜杠字面值,用戶可能必須寫成 '\\\\' 來作為模式字符串,因為正則表達(dá)式必須為 \\,而每個反斜杠在普通 Python 字符串字面值中又必須表示為 \\。 而且還要注意,在 Python 的字符串字面值中使用的反斜杠如果有任何無效的轉(zhuǎn)義序列,現(xiàn)在會觸發(fā) DeprecationWarning,但以后會改為 SyntaxError。 此行為即使對于正則表達(dá)式來說有效的轉(zhuǎn)義字符同樣會發(fā)生。

解決辦法是對于正則表達(dá)式樣式使用 Python 的原始字符串表示法;在帶有 'r' 前綴的字符串字面值中,反斜杠不必做任何特殊處理。 因此 r"\n" 表示包含 '\''n' 兩個字符的字符串,而 "\n" 則表示只包含一個換行符的字符串。 樣式在 Python 代碼中通常都使用原始字符串表示法。

絕大多數(shù)正則表達(dá)式操作都提供為模塊函數(shù)和方法,在 編譯正則表達(dá)式. 這些函數(shù)是一個捷徑,不需要先編譯正則對象,但是損失了一些優(yōu)化參數(shù)。

參見

第三方模塊 regex , 提供了與標(biāo)準(zhǔn)庫 re 模塊兼容的 API 接口,同時,還提供了更多功能和更全面的 Unicode 支持。

正則表達(dá)式語法?

正則表達(dá)式(或 RE)指定了一組與之匹配的字符串;模塊內(nèi)的函數(shù)可以檢查某個字符串是否與給定的正則表達(dá)式匹配(或者正則表達(dá)式是否匹配到字符串,這兩種說法含義相同)。

正則表達(dá)式可以拼接;如果 AB 都是正則表達(dá)式,則 AB 也是正則表達(dá)式。通常,如果字符串 p 匹配 A,并且另一個字符串 q 匹配 B,那么 pq 可以匹配 AB。除非 A 或者 B 包含低優(yōu)先級操作,AB 存在邊界條件;或者命名組引用。所以,復(fù)雜表達(dá)式可以很容易的從這里描述的簡單源語表達(dá)式構(gòu)建。更多正則表達(dá)式理論和實現(xiàn),詳見 the Friedl book [Frie09] ,或者其他構(gòu)建編譯器的書籍。

以下是正則表達(dá)式格式的簡要說明。更詳細(xì)的信息和演示,參考 正則表達(dá)式HOWTO。

正則表達(dá)式可以包含普通或者特殊字符。絕大部分普通字符,比如 'A', 'a', 或者 '0',都是最簡單的正則表達(dá)式。它們就匹配自身。你可以拼接普通字符,所以 last 匹配字符串 'last'. (在這一節(jié)的其他部分,我們將用 this special style 這種方式表示正則表達(dá)式,通常不帶引號,要匹配的字符串用 'in single quotes' ,單引號形式。)

有些字符,比如 '|' 或者 '(',屬于特殊字符。 特殊字符既可以表示它的普通含義, 也可以影響它旁邊的正則表達(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.

特殊字符有:

.

(點) 在默認(rèn)模式,匹配除了換行的任意字符。如果指定了標(biāo)簽 DOTALL ,它將匹配包括換行符的任意字符。

^

(插入符號) 匹配字符串的開頭, 并且在 MULTILINE 模式也匹配換行后的首個符號。

$

匹配字符串尾或者在字符串尾的換行符的前一個字符,在 MULTILINE 模式下也會匹配換行符之前的文本。 foo 匹配 'foo' 和 'foobar',但正則表達(dá)式 foo$ 只匹配 'foo'。 更有趣的是,在 'foo1\nfoo2\n' 中搜索 foo.$,通常匹配 'foo2',但在 MULTILINE 模式下可以匹配到 'foo1';在 'foo\n' 中搜索 $ 會找到兩個(空的)匹配:一個在換行符之前,一個在字符串的末尾。

*

對它前面的正則式匹配0到任意次重復(fù), 盡量多的匹配字符串。 ab* 會匹配 'a','ab',或者 'a' 后面跟隨任意個 'b'。

+

對它前面的正則式匹配1到任意次重復(fù)。 ab+ 會匹配 'a' 后面跟隨1個以上到任意個 'b',它不會匹配 'a'。

?

對它前面的正則式匹配0到1次重復(fù)。 ab? 會匹配 '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 the a* will match all 4 'a's, but, when the final 'a' is encountered, the expression is backtracked so that in the end the a* ends up matching 3 'a's total, and the fourth 'a' is matched by the final 'a'. However, when a*+a is used to match 'aaaa', the a*+ 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++ and x?+ are equivalent to (?>x*), (?>x+) and (?>x?) correspondingly.

3.11 新版功能.

{m}

對其之前的正則式指定匹配 m 個重復(fù);少于 m 的話就會導(dǎo)致匹配失敗。比如, a{6} 將匹配6個 'a' , 但是不能是5個。

{m,n}

對正則式進(jìn)行 mn 次匹配,在 mn 之間取盡量多。 比如,a{3,5} 將匹配 3 到 5個 'a'。忽略 m 意為指定下界為0,忽略 n 指定上界為無限次。 比如 a{4,}b 將匹配 'aaaab' 或者1000個 'a' 尾隨一個 'b',但不能匹配 'aaab'。逗號不能省略,否則無法辨別修飾符應(yīng)該忽略哪個邊界。

{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, while a{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, while a{3,5}aa will match with a{3,5} capturing 5, then 4 'a's by backtracking and then the final 2 'a's are matched by the final aa in the pattern. x{m,n}+ is equivalent to (?>x{m,n}).

3.11 新版功能.

\

轉(zhuǎn)義特殊字符(允許你匹配 '*', '?', 或者此類其他),或者表示一個特殊序列;特殊序列之后進(jìn)行討論。

如果你沒有使用原始字符串( r'raw' )來表達(dá)樣式,要牢記Python也使用反斜杠作為轉(zhuǎn)義序列;如果轉(zhuǎn)義序列不被Python的分析器識別,反斜杠和字符才能出現(xiàn)在字符串中。如果Python可以識別這個序列,那么反斜杠就應(yīng)該重復(fù)兩次。這將導(dǎo)致理解障礙,所以高度推薦,就算是最簡單的表達(dá)式,也要使用原始字符串。

[]

用于表示一個字符集合。在一個集合中:

  • 字符可以單獨列出,比如 [amk] 匹配 'a', 'm', 或者 'k'。

  • 可以表示字符范圍,通過用 '-' 將兩個字符連起來。比如 [a-z] 將匹配任何小寫ASCII字符, [0-5][0-9] 將匹配從 0059 的兩位數(shù)字, [0-9A-Fa-f] 將匹配任何十六進(jìn)制數(shù)位。 如果 - 進(jìn)行了轉(zhuǎn)義 (比如 [a\-z])或者它的位置在首位或者末尾(如 [-a][a-]),它就只表示普通字符 '-'

  • 特殊字符在集合中,失去它的特殊含義。比如 [(+*)] 只會匹配這幾個文法字符 '(', '+', '*', or ')'。

  • 字符類如 \w 或者 \S (如下定義) 在集合內(nèi)可以接受,它們可以匹配的字符由 ASCII 或者 LOCALE 模式?jīng)Q定。

  • 不在集合范圍內(nèi)的字符可以通過 取反 來進(jìn)行匹配。如果集合首字符是 '^' ,所有 在集合內(nèi)的字符將會被匹配,比如 [^5] 將匹配所有字符,除了 '5', [^^] 將匹配所有字符,除了 '^'. ^ 如果不在集合首位,就沒有特殊含義。

  • 在集合內(nèi)要匹配一個字符 ']',有兩種方法,要么就在它之前加上反斜杠,要么就把它放到集合首位。比如, [()[\]{}][]()[{}] 都可以匹配括號。

  • Unicode Technical Standard #18 里的嵌套集合和集合操作支持可能在未來添加。這將會改變語法,所以為了幫助這個改變,一個 FutureWarning 將會在有多義的情況里被 raise,包含以下幾種情況,集合由 '[' 開始,或者包含下列字符序列 '--', '&&', '~~', 和 '||'。為了避免警告,需要將它們用反斜杠轉(zhuǎn)義。

在 3.7 版更改: 如果一個字符串構(gòu)建的語義在未來會改變的話,一個 FutureWarningraise 。

|

A|BAB 可以是任意正則表達(dá)式,創(chuàng)建一個正則表達(dá)式,匹配 A 或者 B. 任意個正則表達(dá)式可以用 '|' 連接。它也可以在組合(見下列)內(nèi)使用。掃描目標(biāo)字符串時, '|' 分隔開的正則樣式從左到右進(jìn)行匹配。當(dāng)一個樣式完全匹配時,這個分支就被接受。意思就是,一旦 A 匹配成功, B 就不再進(jìn)行匹配,即便它能產(chǎn)生一個更好的匹配。或者說,'|' 操作符絕不貪婪。 如果要匹配 '|' 字符,使用 \|, 或者把它包含在字符集里,比如 [|].

(...)

(組合),匹配括號內(nèi)的任意正則表達(dá)式,并標(biāo)識出組合的開始和結(jié)尾。匹配完成后,組合的內(nèi)容可以被獲取,并可以在之后用 \number 轉(zhuǎn)義序列進(jìn)行再次匹配,之后進(jìn)行詳細(xì)說明。要匹配字符 '(' 或者 ')', 用 \(\), 或者把它們包含在字符集合里: [(], [)].

(?…)

這是個擴(kuò)展標(biāo)記法 (一個 '?' 跟隨 '(' 并無含義)。 '?' 后面的第一個字符決定了這個構(gòu)建采用什么樣的語法。這種擴(kuò)展通常并不創(chuàng)建新的組合; (?P<name>...) 是唯一的例外。 以下是目前支持的擴(kuò)展。

(?aiLmsux)

( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一個或多個) 這個組合匹配一個空字符串;這些字符對正則表達(dá)式設(shè)置以下標(biāo)記 re.A (只匹配ASCII字符), re.I (忽略大小寫), re.L (語言依賴), re.M (多行模式), re.S (點dot匹配全部字符), re.U (Unicode匹配), and re.X (冗長模式)。 (這些標(biāo)記在 模塊內(nèi)容 中描述) 如果你想將這些標(biāo)記包含在正則表達(dá)式中,這個方法就很有用,免去了在 re.compile() 中傳遞 flag 參數(shù)。標(biāo)記應(yīng)該在表達(dá)式字符串首位表示。

在 3.11 版更改: This construction can only be used at the start of the expression.

(?:…)

正則括號的非捕獲版本。 匹配在括號內(nèi)的任何正則表達(dá)式,但該分組所匹配的子字符串 不能 在執(zhí)行匹配后被獲取或是之后在模式中被引用。

(?aiLmsux-imsx:…)

('a', 'i', 'L', 'm', 's', 'u', 'x' 中的0或者多個, 之后可選跟隨 '-' 在后面跟隨 'i' , 'm' , 's' , 'x' 中的一到多個 .) 這些字符為表達(dá)式的其中一部分 設(shè)置 或者 去除 相應(yīng)標(biāo)記 re.A (只匹配ASCII), re.I (忽略大小寫), re.L (語言依賴), re.M (多行), re.S (點匹配所有字符), re.U (Unicode匹配), and re.X (冗長模式)。(標(biāo)記描述在 模塊內(nèi)容 .)

'a', 'L' and 'u' 作為內(nèi)聯(lián)標(biāo)記是相互排斥的, 所以它們不能結(jié)合在一起,或者跟隨 '-' 。 當(dāng)他們中的某個出現(xiàn)在內(nèi)聯(lián)組中,它就覆蓋了括號組內(nèi)的匹配模式。在Unicode樣式中, (?a:...) 切換為 只匹配ASCII, (?u:...) 切換為Unicode匹配 (默認(rèn)). 在byte樣式中 (?L:...) 切換為語言依賴模式, (?a:...) 切換為 只匹配ASCII (默認(rèn))。這種方式只覆蓋組合內(nèi)匹配,括號外的匹配模式不受影響。

3.6 新版功能.

在 3.7 版更改: 符號 'a', 'L''u' 同樣可以用在一個組合內(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) (也就是說,匹配單引號或者雙引號括起來的字符串):

引用組合 "quote" 的上下文

引用方法

在正則式自身內(nèi)

  • (?P=quote) (如示)

  • \1

處理匹配對象 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)

反向引用一個命名組合;它匹配前面那個叫 name 的命名組中匹配到的串同樣的字串。

(?#…)

注釋;里面的內(nèi)容會被忽略。

(?=…)

匹配 的內(nèi)容,但是并不消費樣式的內(nèi)容。這個叫做 lookahead assertion。比如, Isaac (?=Asimov) 匹配 'Isaac ' 只有在后面是 'Asimov' 的時候。

(?!…)

匹配 不符合的情況。這個叫 negative lookahead assertion (前視取反)。比如說, Isaac (?!Asimov) 只有后面 'Asimov' 的時候才匹配 'Isaac ' 。

(?<=…)

匹配字符串的當(dāng)前位置,它的前面匹配 ... 的內(nèi)容到當(dāng)前位置。這叫 positive lookbehind assertion (正向后視斷定)。 (?<=abc)def 會在 'abcdef' 中找到一個匹配,因為后視會往后看3個字符并檢查是否包含匹配的樣式。包含的匹配樣式必須是定長的,意思就是 abca|b 是允許的,但是 a*a{3,4} 不可以。注意以 positive lookbehind assertions 開始的樣式,如 (?<=abc)def ,并不是從 a 開始搜索,而是從 d 往回看的。你可能更加愿意使用 search() 函數(shù),而不是 match() 函數(shù):

>>>
>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'

這個例子搜索一個跟隨在連字符后的單詞:

>>>
>>> m = re.search(r'(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

在 3.5 版更改: 添加定長組合引用的支持。

(?<!…)

匹配當(dāng)前位置之前不是 ... 的樣式。這個叫 negative lookbehind assertion (后視斷定取非)。類似正向后視斷定,包含的樣式匹配必須是定長的。由 negative lookbehind assertion 開始的樣式可以從字符串搜索開始的位置進(jìn)行匹配。

(?(id/name)yes-pattern|no-pattern)

如果給定的 idname 存在,將會嘗試匹配 yes-pattern ,否則就嘗試匹配 no-patternno-pattern 可選,也可以被忽略。比如, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) 是一個email樣式匹配,將匹配 '<user@host.com>''user@host.com' ,但不會匹配 '<user@host.com' ,也不會匹配 'user@host.com>'。

在 3.12 版更改: Group id can only contain ASCII digits.

'\' 和一個字符組成的特殊序列在以下列出。 如果普通字符不是ASCII數(shù)位或者ASCII字母,那么正則樣式將匹配第二個字符。比如,\$ 匹配字符 '$'.

\number

匹配數(shù)字代表的組合。每個括號是一個組合,組合從1開始編號。比如 (.+) \1 匹配 'the the' 或者 '55 55', 但不會匹配 'thethe' (注意組合后面的空格)。這個特殊序列只能用于匹配前面99個組合。如果 number 的第一個數(shù)位是0, 或者 number 是三個八進(jìn)制數(shù),它將不會被看作是一個組合,而是八進(jìn)制的數(shù)字值。在 '['']' 字符集合內(nèi),任何數(shù)字轉(zhuǎn)義都被看作是字符。

\A

只匹配字符串開始。

\b

匹配空字符串,但只在單詞開始或結(jié)尾的位置。一個單詞被定義為一個單詞字符的序列。注意,通常 \b 定義為 \w\W 字符之間,或者 \w 和字符串開始/結(jié)尾的邊界, 意思就是 r'\bfoo\b' 匹配 'foo', 'foo.', '(foo)', 'bar foo baz' 但不匹配 'foobar' 或者 'foo3'。

默認(rèn)情況下,Unicode字母和數(shù)字是在Unicode樣式中使用的,但是可以用 ASCII 標(biāo)記來更改。如果 LOCALE 標(biāo)記被設(shè)置的話,詞的邊界是由當(dāng)前語言區(qū)域設(shè)置決定的,\b 表示退格字符,以便與Python字符串文本兼容。

\B

匹配空字符串,但 能在詞的開頭或者結(jié)尾。意思就是 r'py\B' 匹配 'python', 'py3', 'py2', 但不匹配 'py', 'py.', 或者 'py!'. \B\b 的取非,所以Unicode樣式的詞語是由Unicode字母,數(shù)字或下劃線構(gòu)成的,雖然可以用 ASCII 標(biāo)志來改變。如果使用了 LOCALE 標(biāo)志,則詞的邊界由當(dāng)前語言區(qū)域設(shè)置。

\d
對于 Unicode (str) 樣式:

匹配任何Unicode十進(jìn)制數(shù)(就是在Unicode字符目錄[Nd]里的字符)。這包括了 [0-9] ,和很多其他的數(shù)字字符。如果設(shè)置了 ASCII 標(biāo)志,就只匹配 [0-9]

對于8位(bytes)樣式:

匹配任何十進(jìn)制數(shù),就是 [0-9]。

\D

匹配任何非十進(jìn)制數(shù)字的字符。就是 \d 取非。 如果設(shè)置了 ASCII 標(biāo)志,就相當(dāng)于 [^0-9] 。

\s
對于 Unicode (str) 樣式:

匹配任何Unicode空白字符(包括 [ \t\n\r\f\v] ,還有很多其他字符,比如不同語言排版規(guī)則約定的不換行空格)。如果 ASCII 被設(shè)置,就只匹配 [ \t\n\r\f\v] 。

對于8位(bytes)樣式:

匹配ASCII中的空白字符,就是 [ \t\n\r\f\v] 。

\S

匹配任何非空白字符。就是 \s 取非。如果設(shè)置了 ASCII 標(biāo)志,就相當(dāng)于 [^ \t\n\r\f\v] 。

\w
對于 Unicode (str) 樣式:

匹配Unicode詞語的字符,包含了可以構(gòu)成詞語的絕大部分字符,也包括數(shù)字和下劃線。如果設(shè)置了 ASCII 標(biāo)志,就只匹配 [a-zA-Z0-9_] 。

對于8位(bytes)樣式:

匹配ASCII字符中的數(shù)字和字母和下劃線,就是 [a-zA-Z0-9_] 。如果設(shè)置了 LOCALE 標(biāo)記,就匹配當(dāng)前語言區(qū)域的數(shù)字和字母和下劃線。

\W

匹配非單詞字符的字符。這與 \w 正相反。如果使用了 ASCII 旗標(biāo),這就等價于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗標(biāo),則會匹配當(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 被用于表示詞語的邊界,它只在字符集合內(nèi)表示退格,比如 [\b] 。)

'\u', '\U''\N' 轉(zhuǎn)義序列只在 Unicode 模式中可被識別。 在 bytes 模式中它們會導(dǎo)致錯誤。 未知的 ASCII 字母轉(zhuǎn)義序列保留在未來使用,會被當(dāng)作錯誤來處理。

八進(jìn)制轉(zhuǎn)義包含為一個有限形式。如果首位數(shù)字是 0, 或者有三個八進(jìn)制數(shù)位,那么就認(rèn)為它是八進(jìn)制轉(zhuǎn)義。其他的情況,就看作是組引用。對于字符串文本,八進(jìn)制轉(zhuǎn)義最多有三個數(shù)位長。

在 3.3 版更改: 增加了 '\u''\U' 轉(zhuǎn)義序列。

在 3.6 版更改: '\' 和一個ASCII字符組成的未知轉(zhuǎn)義會被看成錯誤。

在 3.8 版更改: 添加了 '\N{name}' 轉(zhuǎn)義序列。 與在字符串字面值中一樣,它擴(kuò)展了命名 Unicode 字符 (例如 '\N{EM DASH}')。

模塊內(nèi)容?

模塊定義了幾個函數(shù)、常量,和一個異常。有些函數(shù)是編譯后的正則表達(dá)式方法的簡化版本(少了一些特性)。重要的應(yīng)用程序大多會在使用前先編譯正則表達(dá)式。

Flags?

在 3.6 版更改: 標(biāo)志常量現(xiàn)在是 RegexFlag 類的實例,這個類是 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。這只對Unicode樣式有效,會被byte樣式忽略。相當(dāng)于前面語法中的內(nèi)聯(lián)標(biāo)志 (?a)

注意,為了保持向后兼容, re.U 標(biāo)記依然存在(還有他的同義 re.UNICODE 和嵌入形式 (?u) ) , 但是這些在 Python 3 是冗余的,因為默認(rèn)字符串已經(jīng)是Unicode了(并且Unicode匹配不允許byte出現(xiàn))。

re.DEBUG?

顯示編譯時的debug信息,沒有內(nèi)聯(lián)標(biāo)記。

re.I?
re.IGNORECASE?

進(jìn)行忽略大小寫匹配;表達(dá)式如 [A-Z] 也會匹配小寫字符。Unicode匹配(比如 ü 匹配 ü)同樣有用,除非設(shè)置了 re.ASCII 標(biāo)記來禁用非ASCII匹配。當(dāng)前語言區(qū)域不會改變這個標(biāo)記,除非設(shè)置了 re.LOCALE 標(biāo)記。這個相當(dāng)于內(nèi)聯(lián)標(biāo)記 (?i)

注意,當(dāng)設(shè)置了 IGNORECASE 標(biāo)記,搜索Unicode樣式 [a-z][A-Z] 的結(jié)合時,它將會匹配52個ASCII字符和4個額外的非ASCII字符: '?' (U+0130, 拉丁大寫的 I 帶個點在上面), '?' (U+0131, 拉丁小寫沒有點的 I ), '?' (U+017F, 拉丁小寫長 s) and 'K' (U+212A, 開爾文符號).如果使用 ASCII 標(biāo)記,就只匹配 'a' 到 'z' 和 'A' 到 'Z' 。

re.L?
re.LOCALE?

由當(dāng)前語言區(qū)域決定 \w, \W, \b, \B 和大小寫敏感匹配。這個標(biāo)記只能對byte樣式有效。這個標(biāo)記不推薦使用,因為語言區(qū)域機(jī)制很不可靠,它一次只能處理一個 "習(xí)慣”,而且只對8位字節(jié)有效。Unicode匹配在Python 3 里默認(rèn)啟用,并可以處理不同語言。 這個對應(yīng)內(nèi)聯(lián)標(biāo)記 (?L) 。

在 3.6 版更改: re.LOCALE 只能用于byte樣式,而且不能和 re.ASCII 一起用。

在 3.7 版更改: 設(shè)置了 re.LOCALE 標(biāo)記的編譯正則對象不再在編譯時依賴語言區(qū)域設(shè)置。語言區(qū)域設(shè)置只在匹配的時候影響其結(jié)果。

re.M?
re.MULTILINE?

設(shè)置以后,樣式字符 '^' 匹配字符串的開始,和每一行的開始(換行符后面緊跟的符號);樣式字符 '$' 匹配字符串尾,和每一行的結(jié)尾(換行符前面那個符號)。默認(rèn)情況下,’^’ 匹配字符串頭,'$' 匹配字符串尾。對應(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?

'.' 特殊字符匹配任何字符,包括換行符;如果沒有這個標(biāo)記,'.' 就匹配 除了 換行符的其他任意字符。對應(yīng)內(nèi)聯(lián)標(biāo)記 (?s) 。

re.X?
re.VERBOSE?

這個標(biāo)記允許你編寫更具可讀性更友好的正則表達(dá)式。通過分段和添加注釋。空白符號會被忽略,除非在一個字符集合當(dāng)中或者由反斜杠轉(zhuǎn)義,或者在 *?, (?: or (?P<…> 分組之內(nèi)。當(dāng)一個行內(nèi)有 # 不在字符集和轉(zhuǎn)義序列,那么它之后的所有字符都是注釋。

意思就是下面兩個正則表達(dá)式等價地匹配一個十進(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*")

對應(yīng)內(nèi)聯(lián)標(biāo)記 (?x)

Functions?

re.compile(pattern, flags=0)?

將正則表達(dá)式的樣式編譯為一個 正則表達(dá)式對象 (正則對象),可以用于匹配,通過這個對象的方法 match(), search() 以及其他如下描述。

這個表達(dá)式的行為可以通過指定 標(biāo)記 的值來改變。值可以是以下任意變量,可以通過位的OR操作來結(jié)合( | 操作符)。

序列

prog = re.compile(pattern)
result = prog.match(string)

等價于

result = re.match(pattern, string)

如果需要多次使用這個正則表達(dá)式的話,使用 re.compile() 和保存這個正則對象以便復(fù)用,可以讓程序更加高效。

備注

通過 re.compile() 編譯后的樣式,和模塊級的函數(shù)會被緩存, 所以少數(shù)的正則表達(dá)式使用無需考慮編譯的問題。

re.search(pattern, string, flags=0)?

掃描整個 字符串 找到匹配樣式的第一個位置,并返回一個相應(yīng)的 匹配對象。如果沒有匹配,就返回一個 None ; 注意這和找到一個零長度匹配是不同的。

re.match(pattern, string, flags=0)?

如果 string 開始的0或者多個字符匹配到了正則表達(dá)式樣式,就返回一個相應(yīng)的 匹配對象 。 如果沒有匹配,就返回 None ;注意它跟零長度匹配是不同的。

注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的開始位置,而不匹配每行開始。

如果你想定位 string 的任何位置,使用 search() 來替代(也可參考 search() vs. match()

re.fullmatch(pattern, string, flags=0)?

如果整個 string 匹配到正則表達(dá)式樣式,就返回一個相應(yīng)的 匹配對象 。 否則就返回一個 None ;注意這跟零長度匹配是不同的。

3.4 新版功能.

re.split(pattern, string, maxsplit=0, flags=0)?

pattern 分開 string 。 如果在 pattern 中捕獲到括號,那么所有的組里的文字也會包含在列表里。如果 maxsplit 非零, 最多進(jìn)行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一個元素。

>>>
>>> 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']

如果分隔符里有捕獲組合,并且匹配到字符串的開始,那么結(jié)果將會以一個空字符串開始。對于結(jié)尾也是一樣

>>>
>>> re.split(r'(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']

這樣的話,分隔組將會出現(xiàn)在結(jié)果列表中同樣的位置。

樣式的空匹配僅在與前一個空匹配不相鄰時才會拆分字符串。

>>>
>>> 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)在可以在前一個空匹配之后出現(xiàn)了。

re.finditer(pattern, string, flags=0)?

patternstring 里所有的非重復(fù)匹配,返回為一個迭代器 iterator 保存了 匹配對象 。 string 從左到右掃描,匹配按順序排列??掌ヅ湟舶诮Y(jié)果里。

在 3.7 版更改: 非空匹配現(xiàn)在可以在前一個空匹配之后出現(xiàn)了。

re.sub(pattern, repl, string, count=0, flags=0)?

返回通過使用 repl 替換在 string 最左邊非重疊出現(xiàn)的 pattern 而獲得的字符串。 如果樣式?jīng)]有找到,則不加改變地返回 stringrepl 可以是字符串或函數(shù);如為字符串,則其中任何反斜杠轉(zhuǎn)義序列都會被處理。 也就是說,\n 會被轉(zhuǎn)換為一個換行符,\r 會被轉(zhuǎn)換為一個回車符,依此類推。 未知的 ASCII 字符轉(zhuǎn)義序列保留在未來使用,會被當(dāng)作錯誤來處理。 其他未知轉(zhuǎn)義序列例如 \& 會保持原樣。 向后引用像是 \6 會用樣式中第 6 組所匹配到的子字符串來替換。 例如:

>>>
>>> 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 是一個函數(shù),那它會對每個非重復(fù)的 pattern 的情況調(diào)用。這個函數(shù)只能有一個 匹配對象 參數(shù),并返回一個替換后的字符串。比如

>>>
>>> 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'

樣式可以是一個字符串或者一個 樣式對象 。

可選參數(shù) count 是要替換的最大次數(shù);count 必須是非負(fù)整數(shù)。如果省略這個參數(shù)或設(shè)為 0,所有的匹配都會被替換。 樣式的空匹配僅在與前一個空匹配不相鄰時才會被替換,所以 sub('x*', '-', 'abxd') 返回 '-a-b--d-' 。

在字符串類型的 repl 參數(shù)里,如上所述的轉(zhuǎn)義和向后引用中,\g<name> 會使用命名組合 name,(在 (?P<name>…) 語法中定義) \g<number> 會使用數(shù)字組;\g<2> 就是 \2,但它避免了二義性,如 \g<2>0。 \20 就會被解釋為組20,而不是組2后面跟隨一個字符 '0'。向后引用 \g<0>pattern 作為一整個組進(jìn)行引用。

在 3.1 版更改: 增加了可選標(biāo)記參數(shù)。

在 3.5 版更改: 不匹配的組合替換為空字符串。

在 3.6 版更改: pattern 中的未知轉(zhuǎn)義(由 '\' 和一個 ASCII 字符組成)被視為錯誤。

在 3.7 版更改: repl 中的未知轉(zhuǎn)義(由 '\' 和一個 ASCII 字符組成)被視為錯誤。

在 3.7 版更改: 樣式中的空匹配相鄰接時會被替換。

在 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() 相同,但是返回一個元組 (字符串, 替換次數(shù)).

在 3.1 版更改: 增加了可選標(biāo)記參數(shù)。

在 3.5 版更改: 不匹配的組合替換為空字符串。

re.escape(pattern)?

轉(zhuǎn)義 pattern 中的特殊字符。如果你想對任意可能包含正則表達(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))))
/|\-|\+|\*\*|\*

這個函數(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á)式中具有特殊含義的字符才會被轉(zhuǎn)義。 因此, '!', '"', '%', "'", ',', '/', ':', ';', '<', '=', '>', '@'"`" 將不再會被轉(zhuǎn)義。

re.purge()?

清除正則表達(dá)式的緩存。

Exceptions?

exception re.error(msg, pattern=None, pos=None)?

當(dāng)傳遞給函數(shù)的正則表達(dá)式不合法(比如括號不匹配),或者在編譯或匹配過程中出現(xiàn)其他錯誤時,會引發(fā)異常。所給字符串不匹配所給模式不會引發(fā)異常。異常實例有以下附加屬性:

msg?

未格式化的錯誤消息。

pattern?

正則表達(dá)式的模式串。

pos?

編譯失敗的 pattern 的位置索引(可以是 None )。

lineno?

對應(yīng) pos (可以是 None) 的行號。

colno?

對應(yīng) pos (可以是 None) 的列號。

在 3.5 版更改: 增加了額外的屬性。

正則表達(dá)式對象 (正則對象)?

編譯后的正則表達(dá)式對象支持以下方法和屬性:

Pattern.search(string[, pos[, endpos]])?

掃描整個 string 尋找第一個匹配的位置, 并返回一個相應(yīng)的 匹配對象。如果沒有匹配,就返回 None ;注意它和零長度匹配是不同的。

可選的第二個參數(shù) pos 給出了字符串中開始搜索的位置索引;默認(rèn)為 0,它不完全等價于字符串切片; '^' 樣式字符匹配字符串真正的開頭,和換行符后面的第一個字符,但不會匹配索引規(guī)定開始的位置。

可選參數(shù) endpos 限定了字符串搜索的結(jié)束;它假定字符串長度到 endpos , 所以只有從 posendpos - 1 的字符會被匹配。如果 endpos 小于 pos,就不會有匹配產(chǎn)生;另外,如果 rx 是一個編譯后的正則對象, rx.search(string, 0, 50) 等價于 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開始位置 能夠找到這個正則樣式的任意個匹配,就返回一個相應(yīng)的 匹配對象。如果不匹配,就返回 None ;注意它與零長度匹配是不同的。

可選參數(shù) posendpossearch() 含義相同。

>>>
>>> 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() 來替代(另參考 search() vs. match())。

Pattern.fullmatch(string[, pos[, endpos]])?

如果整個 string 匹配這個正則表達(dá)式,就返回一個相應(yīng)的 匹配對象 。 否則就返回 None ; 注意跟零長度匹配是不同的。

可選參數(shù) posendpossearch() 含義相同。

>>>
>>> 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.split(string, maxsplit=0)?

等價于 split() 函數(shù),使用了編譯后的樣式。

Pattern.findall(string[, pos[, endpos]])?

類似函數(shù) findall() , 使用了編譯后樣式,但也可以接收可選參數(shù) posendpos ,限制搜索范圍,就像 search()

Pattern.finditer(string[, pos[, endpos]])?

類似函數(shù) finditer() , 使用了編譯后樣式,但也可以接收可選參數(shù) posendpos ,限制搜索范圍,就像 search()。

Pattern.sub(repl, string, count=0)?

等價于 sub() 函數(shù),使用了編譯后的樣式。

Pattern.subn(repl, string, count=0)?

等價于 subn() 函數(shù),使用了編譯后的樣式。

Pattern.flags?

正則匹配標(biāo)記。這是可以傳遞給 compile() 的參數(shù),任何 (?…) 內(nèi)聯(lián)標(biāo)記,隱性標(biāo)記比如 UNICODE 的結(jié)合。

Pattern.groups?

捕獲到的模式串中組的數(shù)量。

Pattern.groupindex?

映射由 (?P<id>) 定義的命名符號組合和數(shù)字組合的字典。如果沒有符號組,那字典就是空的。

Pattern.pattern?

編譯對象的原始樣式字符串。

在 3.7 版更改: 添加 copy.copy()copy.deepcopy() 函數(shù)的支持。編譯后的正則表達(dá)式對象被認(rèn)為是原子性的。

匹配對象?

匹配對象總是有一個布爾值 True。如果沒有匹配的話 match()search() 返回 None 所以你可以簡單的用 if 語句來判斷是否匹配

match = re.search(pattern, string)
if match:
    process(match)

匹配對象支持以下方法和屬性:

Match.expand(template)?

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, ...])?

返回一個或者多個匹配的子組。如果只有一個參數(shù),結(jié)果就是一個字符串,如果有多個參數(shù),結(jié)果就是一個元組(每個參數(shù)對應(yīng)一個項),如果沒有參數(shù),組1默認(rèn)到0(整個匹配都被返回)。 如果一個組N 參數(shù)值為 0,相應(yīng)的返回值就是整個匹配字符串;如果它是一個范圍 [1..99],結(jié)果就是相應(yīng)的括號組字符串。如果一個組號是負(fù)數(shù),或者大于樣式中定義的組數(shù),就引發(fā)一個 IndexError 異常。如果一個組包含在樣式的一部分,并被匹配多次,就返回最后一個匹配。:

>>>
>>> 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>...) 語法, groupN 參數(shù)就也可能是命名組合的名字。如果一個字符串參數(shù)在樣式中未定義為組合名,就引發(fā)一個 IndexError 異常。

一個相對復(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'

命名組合同樣可以通過索引值引用

>>>
>>> m.group(1)
'Malcolm'
>>> m.group(2)
'Reynolds'

如果一個組匹配成功多次,就只返回最后一個匹配

>>>
>>> m = re.match(r"(..)+", "a1b2c3")  # Matches 3 times.
>>> m.group(1)                        # Returns only the last match.
'c3'
Match.__getitem__(g)?

這個等價于 m.group(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)?

返回一個元組,包含所有匹配的子組,在樣式中出現(xiàn)的從1到任意多的組合。 default 參數(shù)用于不參與匹配的情況,默認(rèn)為 None。

例如:

>>>
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')

如果我們使小數(shù)點可選,那么不是所有的組都會參與到匹配當(dāng)中。這些組合默認(rèn)會返回一個 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)?

返回一個字典,包含了所有的 命名 子組。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 匹配到的字串的開始和結(jié)束標(biāo)號。group 默認(rèn)為0(意思是整個匹配的子串)。如果 group 存在,但未產(chǎn)生匹配,就返回 -1 。對于一個匹配對象 m, 和一個未參與匹配的組 g ,組 g (等價于 m.group(g))產(chǎn)生的匹配是

m.string[m.start(g):m.end(g)]

注意 m.start(group) 將會等于 m.end(group) ,如果 group 匹配一個空字符串的話。比如,在 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ā)一個 IndexError 異常。

這個例子會從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])?

對于一個匹配 m , 返回一個二元組 (m.start(group), m.end(group)) 。 注意如果 group 沒有在這個匹配中,就返回 (-1, -1)group 默認(rèn)為0,就是整個匹配。

Match.pos?

pos 的值,會傳遞給 search()match() 的方法 a 正則對象 。這個是正則引擎開始在字符串搜索一個匹配的索引位置。

Match.endpos?

endpos 的值,會傳遞給 search()match() 的方法 a 正則對象 。這個是正則引擎停止在字符串搜索一個匹配的索引位置。

Match.lastindex?

捕獲組的最后一個匹配的整數(shù)索引值,或者 None 如果沒有匹配產(chǎn)生的話。比如,對于字符串 'ab',表達(dá)式 (a)b, ((a)(b)), 和 ((ab)) 將得到 lastindex == 1 , 而 (a)(b) 會得到 lastindex == 2

Match.lastgroup?

最后一個匹配的命名組名字,或者 None 如果沒有產(chǎn)生匹配的話。

Match.re?

返回產(chǎn)生這個實例的 正則對象 , 這個實例是由 正則對象的 match()search() 方法產(chǎn)生的。

Match.string?

傳遞到 match()search() 的字符串。

在 3.7 版更改: 添加了對 copy.copy()copy.deepcopy() 的支持。匹配對象被看作是原子性的。

正則表達(dá)式例子?

檢查對子?

在這個例子里,我們使用以下輔助函數(shù)來更好地顯示匹配對象:

def displaymatch(match):
    if match is None:
        return None
    return '<Match: %r, groups=%r>' % (match.group(), match.groups())

假設(shè)你在寫一個撲克程序,一個玩家的一手牌為五個字符的串,每個字符表示一張牌,"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" ,包含了一個對子,或者兩張同樣數(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',)>"

要找出對子由什么牌組成,開發(fā)者可以按照下面的方式來使用匹配對象的 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 目前沒有一個類似c函數(shù) scanf() 的替代品。正則表達(dá)式通常比 scanf() 格式字符串要更強(qiáng)大一些,但也帶來更多復(fù)雜性。下面的表格提供了 scanf() 格式符和正則表達(dá)式大致相同的映射。

scanf() 格式符

正則表達(dá)式

%c

.

%5c

.{5}

%d

[-+]?\d+

%e, %E, %f, %g

[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?

%i

[-+]?(0[xX][\dA-Fa-f]+|0[0-7]*|\d+)

%o

[-+]?[0-7]+

%s

\S+

%u

\d+

%x, %X

[-+]?(0[xX])?[\dA-Fa-f]+

從文件名和數(shù)字提取字符串

/usr/sbin/sendmail - 0 errors, 4 warnings

你可以使用 scanf() 格式化

%s - %d errors, %d warnings

等價的正則表達(dá)式是:

(\S+) - (\d+) errors, (\d+) warnings

search() vs. match()?

Python 提供了兩種不同的操作:基于 re.match() 檢查字符串開頭,或者 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() 中,可以用 '^' 作為開始來限制匹配到字符串的首位

>>>
>>> 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() 只匹配字符串的開始,但使用 search() 和以 '^' 開始的正則表達(dá)式會匹配每行的開始

>>>
>>> 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'>

制作一個電話本?

split() 將字符串用參數(shù)傳遞的樣式分隔開。這個方法對于轉(zhuǎn)換文本數(shù)據(jù)到易讀而且容易修改的數(shù)據(jù)結(jié)構(gòu),是很有用的,如下面的例子證明。

首先,這里是輸入。 它通常來自一個文件,這里我們使用三重引號字符串語法

>>>
>>> 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"""

條目用一個或者多個換行符分開?,F(xiàn)在我們將字符串轉(zhuǎn)換為一個列表,每個非空行都有一個條目:

>>>
>>> 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']

最終,將每個條目分割為一個由名字、姓氏、電話號碼和地址組成的列表。我們?yōu)?split() 使用了 maxsplit 形參,因為地址中包含有被我們作為分割模式的空格符:

>>>
>>> [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']]

:? 樣式匹配姓后面的冒號,因此它不出現(xiàn)在結(jié)果列表中。如果 maxsplit 設(shè)置為 4 ,我們還可以從地址中獲取到房間號:

>>>
>>> [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)的樣式的每一個實例。這個例子證明了使用 sub() 來整理文字,或者隨機(jī)化每個字符的位置,除了首位和末尾字符

>>>
>>> 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() 中的第一個匹配。比如,如果一個作者希望找到文字中的所有副詞,他可能會按照以下方法用 findall()

>>>
>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly\b", text)
['carefully', 'quickly']

查找所有的副詞及其位置?

如果需要匹配樣式的更多信息, finditer() 可以起到作用,它提供了 匹配對象 作為返回值,而不是字符串。繼續(xù)上面的例子,如果一個作者希望找到所有副詞和它的位置,可以按照下面方法使用 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á)式正常。否則,每個正則式里的反斜杠('\') 都必須前綴一個反斜杠來轉(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)需要匹配一個字符反斜杠,它必須在正則表達(dá)式中轉(zhuǎn)義。在原始字符串記法,就是 r"\\"。否則就必須用 "\\\\",來表示同樣的意思

>>>
>>> re.match(r"\\", r"\\")
<re.Match object; span=(0, 1), match='\\'>
>>> re.match("\\\\", r"\\")
<re.Match object; span=(0, 1), match='\\'>

寫一個詞法分析器?

一個 詞法器或詞法分析器 分析字符串,并分類成目錄組。 這是寫一個編譯器或解釋器的第一步。

文字目錄是由正則表達(dá)式指定的。這個技術(shù)是通過將這些樣式合并為一個主正則式,并且循環(huán)匹配來實現(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á)式模式串的編寫。