正則表達式(RegEx)官方手冊/權威指南【Python】

前言

 

 

 

正則表達式(稱爲RE,或正則,或正則表達式模式)本質上是嵌入在Python中的一種微小的、高度專業化的編程語言,可經過 re 模塊得到。 使用這種小語言,你能夠爲要匹配的可能字符串集指定規則;此集可能包含英語句子,電子郵件地址,TeX命令或你喜歡的任何內容。 而後,您能夠詢問諸如「此字符串是否與模式匹配?」或「此字符串中的模式是否匹配?」等問題。 你還可使用正則修改字符串或以各類方式將其拆分。html

正則表達式模式被編譯成一系列字節碼,而後由用 C 編寫的匹配引擎執行。對於高級用途,可能須要特別注意引擎如何執行給定的正則,並將正則寫入以某種方式生成運行速度更快的字節碼。 本文檔未涉及優化,由於它要求你充分了解匹配引擎的內部結構。python

正則表達式語言相對較小且受限制,所以並不是全部可能的字符串處理任務均可以使用正則表達式完成。 還有一些任務 能夠 用正則表達式完成,但表達式變得很是複雜。 在這些狀況下,你最好編寫 Python 代碼來進行處理;雖然 Python 代碼比精心設計的正則表達式慢,但它也可能更容易理解。git

源代碼參考 : Lib/re.pygithub


這個模塊提供了與 Perl 語言相似的正則表達式匹配操做。正則表達式

模式和被搜索的字符串既能夠是 Unicode 字符串 (str) ,也能夠是8位字節串 (bytes)。 可是,Unicode 字符串與8位字節串不能混用:也就是說,你不能用一個字節串模式去匹配 Unicode 字符串,反之亦然;相似地,當進行替換操做時,替換字符串的類型也必須與所用的模式和搜索字符串的類型一致。shell

正則表達式使用反斜槓字符 ('\') 來表示特殊形式或是容許在使用特殊字符時不引起它們的特殊含義。 這會與 Python 的字符串字面值中對相同字符出於相同目的的用法產生衝突;例如,要匹配一個反斜槓字面值,用戶可能必須寫成 '\\\\' 來做爲模式字符串,由於正則表達式必須爲 \\,而每一個反斜槓在普通 Python 字符串字面值中又必須表示爲 \\。 並且還要注意,在 Python 的字符串字面值中使用的反斜槓若是有任何無效的轉義序列,如今將會產生 DeprecationWarning 並將在將來改成 SyntaxError。 此行爲即便對於正則表達式來講有效的轉義字符一樣會發生。編程

解決辦法是對於正則表達式樣式使用 Python 的原始字符串表示法;在帶有 'r' 前綴的字符串字面值中,反斜槓沒必要作任何特殊處理。 所以 r"\n" 表示包含 '\' 和 'n' 兩個字符的字符串,而 "\n" 則表示只包含一個換行符的字符串。 樣式在 Python 代碼中一般都會使用這種原始字符串表示法來表示。緩存

絕大部分正則表達式操做都提供爲模塊函數和方法,在 編譯正則表達式. 這些函數是一個捷徑,不須要先編譯一個正則對象,可是損失了一些優化參數。數據結構

參見dom

 

第三方模塊 regex , 提供了與標準庫 re 模塊兼容的API接口, 同時還提供了額外的功能和更全面的Unicode支持。

正則表達式語法

 

 

一個正則表達式(或RE)指定了一集與之匹配的字符串;模塊內的函數可讓你檢查某個字符串是否跟給定的正則表達式匹配(或者一個正則表達式是否匹配到一個字符串,這兩種說法含義相同)。

正則表達式能夠拼接; 若是 A 和 B 都是正則表達式, 那麼 AB 也是正則表達式。 一般, 若是字符串 p 匹配 A 而且另外一個字符串 q 匹配 B, 那麼 pq 能夠匹配 AB。除非 A 或者 B 包含低優先級操做,A 和 B 存在邊界條件;或者命名組引用。因此,複雜表達式能夠很容易的從這裏描述的簡單源語表達式構建。 瞭解更多正則表達式理論和實現,參考the Friedl book [Frie09] ,或者其餘編譯器構建的書籍。

如下是正則表達式格式的簡要說明。更詳細的信息和演示,參考 正則表達式HOWTO

正則表達式能夠包含普通或者特殊字符。絕大部分普通字符,好比 'A''a', 或者 '0',都是最簡單的正則表達式。它們就匹配自身。你能夠拼接普通字符,因此 last 匹配字符串 'last'. (在這一節的其餘部分,咱們將用 this special style 這種方式表示正則表達式,一般不帶引號,要匹配的字符串用 'in single quotes' ,單引號形式。)

有些字符,好比 '|' 或者 '(',屬於特殊字符。 特殊字符既能夠表示它的普通含義, 也能夠影響它旁邊的正則表達式的解釋。

重複修飾符 (*+?{m,n}, 等) 不能直接嵌套。這樣避免了非貪婪後綴 ? 修飾符,和其餘實現中的修飾符產生的多義性。要應用一個內層重複嵌套,可使用括號。 好比,表達式 (?:a{6})* 匹配6個 'a' 字符重複任意次數。

特殊字符是:

.

(點) 在默認模式,匹配除了換行的任意字符。若是指定了標籤 DOTALL ,它將匹配包括換行符的任意字符。

^

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

$

匹配字符串尾或者換行符的前一個字符,在 MULTILINE 模式匹配換行符的前一個字符。 foo 匹配 'foo' 和 'foobar' , 但正則 foo$ 只匹配 'foo'。更有趣的是, 在 'foo1\nfoo2\n' 搜索 foo.$ ,一般匹配 'foo2' ,但在 MULTILINE 模式 ,能夠匹配到 'foo1' ;在 'foo\n' 搜索 $ 會找到兩個空串:一個在換行前,一個在字符串最後。

*

對它前面的正則式匹配0到任意次重複, 儘可能多的匹配字符串。 ab* 會匹配 'a', 'ab', 或者 'a'``後面跟隨任意個 ``'b'

+

對它前面的正則式匹配1到任意次重複。 ab+ 會匹配 'a' 後面跟隨1個以上到任意個 'b',它不會匹配 'a'

?

對它前面的正則式匹配0到1次重複。 ab? 會匹配 'a' 或者 'ab'

*?+???

'*''+',和 '?' 修飾符都是 貪婪的;它們在字符串進行儘量多的匹配。有時候並不須要這種行爲。若是正則式 <.*> 但願找到 '<a> <c>',它將會匹配整個字符串,而不只是 '<a>'。在修飾符以後添加 ? 將使樣式以 非貪婪`方式或者 :dfn:`最小 方式進行匹配; 儘可能  的字符將會被匹配。 使用正則式 <.*?> 將會僅僅匹配 '<a>'

"{m}"

對其以前的正則式指定匹配 m 個重複;少於 m 的話就會致使匹配失敗。好比, a{6} 將匹配6個 'a' , 可是不能是5個。

"{m, n}"

對正則式進行 m 到 n 次匹配,在 m 和 n 之間取儘可能多。 好比,a{3,5} 將匹配 3 到 5個 'a'。忽略 m 意爲指定下界爲0,忽略 n 指定上界爲無限次。 好比 a{4,}b 將匹配 'aaaab' 或者1000個 'a' 尾隨一個 'b',但不能匹配 'aaab'。逗號不能省略,不然沒法辨別修飾符應該忽略哪一個邊界。

{m,n}?

前一個修飾符的非貪婪模式,只匹配儘可能少的字符次數。好比,對於 'aaaaaa', a{3,5} 匹配 5個 'a' ,而 a{3,5}? 只匹配3個 'a'

\

轉義特殊字符(容許你匹配 '*''?', 或者此類其餘),或者表示一個特殊序列;特殊序列以後進行討論。

若是你沒有使用原始字符串( r'raw' )來表達樣式,要牢記Python也使用反斜槓做爲轉義序列;若是轉義序列不被Python的分析器識別,反斜槓和字符才能出如今字符串中。若是Python能夠識別這個序列,那麼反斜槓就應該重複兩次。這將致使理解障礙,因此高度推薦,就算是最簡單的表達式,也要使用原始字符串。

[]

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

  • 字符能夠單獨列出,好比 [amk] 匹配 'a', 'm', 或者 'k'

  • 能夠表示字符範圍,經過用 '-' 將兩個字符連起來。好比 [a-z] 將匹配任何小寫ASCII字符, [0-5][0-9] 將匹配從 00 到 59 的兩位數字, [0-9A-Fa-f] 將匹配任何十六進制數位。 若是 - 進行了轉義 (好比 [a\-z])或者它的位置在首位或者末尾(如 [-a] 或 [a-]),它就只表示普通字符 '-'

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

  • 字符類如 \w 或者 \S (以下定義) 在集合內能夠接受,它們能夠匹配的字符由 ASCII 或者 LOCALE 模式決定。

  • 不在集合範圍內的字符能夠經過 取反 來進行匹配。若是集合首字符是 '^' ,全部  在集合內的字符將會被匹配,好比 [^5] 將匹配全部字符,除了 '5', [^^] 將匹配全部字符,除了 '^'^ 若是不在集合首位,就沒有特殊含義。

  • 在集合內要匹配一個字符 ']',有兩種方法,要麼就在它以前加上反斜槓,要麼就把它放到集合首位。好比, [()[\]{}] 和 []()[{}] 均可以匹配括號。

  • Unicode Technical Standard #18 裏的嵌套集合和集合操做支持可能在將來添加。這將會改變語法,因此爲了幫助這個改變,一個 FutureWarning 將會在有多義的狀況裏被 raise,包含如下幾種狀況,集合由 '[' 開始,或者包含下列字符序列 '--''&&''~~', 和 '||'。爲了不警告,須要將它們用反斜槓轉義。

在 3.7 版更改: 若是一個字符串構建的語義在將來會改變的話,一個 FutureWarning 會 raise 。

|

A|B, A 和 B 能夠是任意正則表達式,建立一個正則表達式,匹配 A 或者 B. 任意個正則表達式能夠用 '|' 鏈接。它也能夠在組合(見下列)內使用。掃描目標字符串時, '|' 分隔開的正則樣式從左到右進行匹配。當一個樣式徹底匹配時,這個分支就被接受。意思就是,一旦 A 匹配成功, B 就再也不進行匹配,即使它能產生一個更好的匹配。或者說,'|' 操做符毫不貪婪。 若是要匹配 '|' 字符,使用 \|, 或者把它包含在字符集裏,好比 [|].

(...)

(組合),匹配括號內的任意正則表達式,並標識出組合的開始和結尾。匹配完成後,組合的內容能夠被獲取,並能夠在以後用 \number 轉義序列進行再次匹配,以後進行詳細說明。要匹配字符 '(' 或者 ')', 用 \( 或 \), 或者把它們包含在字符集合裏: [(][)].

(?…)

這是個擴展標記法 (一個 '?' 跟隨 '(' 並沒有含義)。 '?' 後面的第一個字符決定了這個構建採用什麼樣的語法。這種擴展一般並不建立新的組合; (?P<name>...) 是惟一的例外。 如下是目前支持的擴展。

(?aiLmsux)

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

(?:…)

正則括號的非捕獲版本。 匹配在括號內的任何正則表達式,但該分組所匹配的子字符串 不能 在執行匹配後被獲取或是以後在模式中被引用。

(?aiLmsux-imsx:…)

('a''i''L''m''s''u''x' 中的0或者多個, 以後可選跟隨 '-' 在後面跟隨 'i' , 'm' , 's' , 'x' 中的一到多個 .) 這些字符爲表達式的其中一部分 設置 或者 去除 相應標記 re.A (只匹配ASCII), re.I (忽略大小寫), re.L (語言依賴), re.M (多行), re.S (點匹配全部字符), re.U (Unicode匹配), and re.X (冗長模式)。(標記描述在 模塊內容 .)

'a''L' and 'u' 做爲內聯標記是相互排斥的, 因此它們不能結合在一塊兒,或者跟隨 '-' 。 當他們中的某個出如今內聯組中,它就覆蓋了括號組內的匹配模式。在Unicode樣式中, (?a:...) 切換爲 只匹配ASCII, (?u:...) 切換爲Unicode匹配 (默認). 在byte樣式中 (?L:...) 切換爲語言依賴模式, (?a:...) 切換爲 只匹配ASCII (默認)。這種方式只覆蓋組合內匹配,括號外的匹配模式不受影響。

3.6 新版功能.

在 3.7 版更改: 符號 'a''L' 和 'u' 一樣能夠用在一個組合內。

(?P<name>…)

(命名組合)相似正則組合,可是匹配到的子串組在外部是經過定義的 name 來獲取的。組合名必須是有效的Python標識符,而且每一個組合名只能用一個正則表達式定義,只能定義一次。一個符號組合一樣是一個數字組合,就像這個組合沒有被命名同樣。

命名組合能夠在三種上下文中引用。若是樣式是 (?P<quote>['"]).*?(?P=quote) (也就是說,匹配單引號或者雙引號括起來的字符串):

引用組合 "quote" 的上下文

引用方法

在正則式自身內

  • (?P=quote) (如示)

  • \1

處理匹配對象 m

  • m.group('quote')

  • m.end('quote') (等)

傳遞到 re.sub() 裏的 repl 參數中

  • \g<quote>

  • \g<1>

  • \1

(?P=name)

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

(?#…)

註釋;裏面的內容會被忽略。

(?=…)

匹配  的內容,可是並不消費樣式的內容。這個叫作 lookahead assertion。好比, Isaac (?=Asimov) 匹配 'Isaac ' 只有在後面是 'Asimov' 的時候。

(?!…)

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

(?<=…)

匹配字符串的當前位置,它的前面匹配  的內容到當前位置。這叫:dfn:positive lookbehind assertion (正向後視判定)。 (?<=abc)def 會在 'abcdef' 中找到一個匹配,由於後視會日後看3個字符並檢查是否包含匹配的樣式。包含的匹配樣式必須是定長的,意思就是 abc 或 a|b 是容許的,可是 a* 和 a{3,4} 不能夠。注意以 positive lookbehind assertions 開始的樣式,如 (?<=abc)def ,並非從 a 開始搜索,而是從 d 往回看的。你可能更加願意使用 search() 函數,而不是 match() 函數:

>>> 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 版更改: 添加定長組合引用的支持。

(?<!…)

匹配當前位置以前不是  的樣式。這個叫:dfn:negative lookbehind assertion (後視判定取非)。相似正向後視判定,包含的樣式匹配必須是定長的。由 negative lookbehind assertion 開始的樣式能夠從字符串搜索開始的位置進行匹配。

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

若是給定的 id 或 name 存在,將會嘗試匹配 yes-pattern ,不然就嘗試匹配 no-patternno-pattern 可選,也能夠被忽略。好比, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) 是一個email樣式匹配,將匹配 '<user@host.com>' 或 'user@host.com' ,但不會匹配 '<user@host.com' ,也不會匹配 'user@host.com>'

由 '\' 和一個字符組成的特殊序列在如下列出。 若是普通字符不是ASCII數位或者ASCII字母,那麼正則樣式將匹配第二個字符。好比,\$ 匹配字符 '$'.

\number

匹配數字表明的組合。每一個括號是一個組合,組合從1開始編號。好比 (.+) \1 匹配 'the the' 或者 '55 55', 但不會匹配 'thethe' (注意組合後面的空格)。這個特殊序列只能用於匹配前面99個組合。若是 number 的第一個數位是0, 或者 number 是三個八進制數,它將不會被看做是一個組合,而是八進制的數字值。在 '[' 和 ']' 字符集合內,任何數字轉義都被看做是字符。

\A

只匹配字符串開始。

\b

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

默認狀況下,Unicode字母和數字是在Unicode樣式中使用的,可是能夠用 ASCII 標記來更改。若是 LOCALE 標記被設置的話,詞的邊界是由當前語言區域設置決定的,\b 表示退格字符,以便與Python字符串文本兼容。

\B

匹配空字符串,但  能在詞的開頭或者結尾。意思就是 r'py\B' 匹配 'python''py3''py2', 但不匹配 'py''py.', 或者 'py!'\B 是 \b 的取非,因此Unicode樣式的詞語是由Unicode字母,數字或下劃線構成的,雖然能夠用 ASCII 標誌來改變。若是使用了 LOCALE 標誌,則詞的邊界由當前語言區域設置。

\d
對於 Unicode (str) 樣式:

匹配任何Unicode十進制數(就是在Unicode字符目錄[Nd]裏的字符)。這包括了 [0-9] ,和不少其餘的數字字符。若是設置了 ASCII 標誌,就只匹配 [0-9] 。

對於8位(bytes)樣式:

匹配任何十進制數,就是 [0-9]

\D

匹配任何非十進制數字的字符。就是 \d 取非。 若是設置了 ASCII 標誌,就至關於 [^0-9] 。

\s
對於 Unicode (str) 樣式:

匹配任何Unicode空白字符(包括 \t\n\r\f\v] ,還有不少其餘字符,好比不一樣語言排版規則約定的不換行空格)。若是 ASCII 被設置,就只匹配 \t\n\r\f\v] 。

對於8位(bytes)樣式:

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

\S

匹配任何非空白字符。就是 \s 取非。若是設置了 ASCII 標誌,就至關於 [^ \t\n\r\f\v] 。

\w
對於 Unicode (str) 樣式:

匹配Unicode詞語的字符,包含了能夠構成詞語的絕大部分字符,也包括數字和下劃線。若是設置了 ASCII 標誌,就只匹配 [a-zA-Z0-9_] 。

對於8位(bytes)樣式:

匹配ASCII字符中的數字和字母和下劃線,就是 [a-zA-Z0-9_] 。若是設置了 LOCALE 標記,就匹配當前語言區域的數字和字母和下劃線。

\W

匹配任何不是單詞字符的字符。 這與 \w 正相反。 若是使用了 ASCII 旗標,這就等價於 [^a-zA-Z0-9_]。 若是使用了 LOCALE 旗標,則會匹配在當前區域設置中不是字母數字又不是下劃線的字符。

\Z

只匹配字符串尾。

絕大部分Python的標準轉義字符也被正則表達式分析器支持。:

\a \b \f \n \N \r \t \u \U \v \x \\ 

(注意 \b 被用於表示詞語的邊界,它只在字符集合內表示退格,好比 [\b] 。)

'\u''\U' 和 '\N' 轉義序列只在 Unicode 模式中可被識別。 在 bytes 模式中它們會致使錯誤。 未知的 ASCII 字母轉義序列保留在將來使用,會被看成錯誤來處理。

八進制轉義包含爲一個有限形式。若是首位數字是 0, 或者有三個八進制數位,那麼就認爲它是八進制轉義。其餘的狀況,就看做是組引用。對於字符串文本,八進制轉義最多有三個數位長。

在 3.3 版更改: 增長了 '\u' 和 '\U' 轉義序列。

在 3.6 版更改: 由 '\' 和一個ASCII字符組成的未知轉義會被當作錯誤。

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

模塊內容

模塊定義了幾個函數,常量,和一個例外。有些函數是編譯後的正則表達式方法的簡化版本(少了一些特性)。絕大部分重要的應用,老是會先將正則表達式編譯,以後在進行操做。

在 3.6 版更改: 標誌常量如今是 RegexFlag 類的實例,這個類是 enum.IntFlag 的子類。

re. compile (patternflags=0)

將正則表達式的樣式編譯爲一個 正則表達式對象 (正則對象),能夠用於匹配,經過這個對象的方法 match()search() 以及其餘以下描述。

這個表達式的行爲能夠經過指定 標記 的值來改變。值能夠是如下任意變量,能夠經過位的OR操做來結合( | 操做符)。

序列

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

等價於

result = re.match(pattern, string) 

若是須要屢次使用這個正則表達式的話,使用 re.compile() 和保存這個正則對象以便複用,可讓程序更加高效。

註解

 

經過 re.compile() 編譯後的樣式,和模塊級的函數會被緩存, 因此少數的正則表達式使用無需考慮編譯的問題。

re. A
re. ASCII

讓 \w\W\b\B\d\D\s 和 \S 只匹配ASCII,而不是Unicode。這隻對Unicode樣式有效,會被byte樣式忽略。至關於前面語法中的內聯標誌 (?a) 。

注意,爲了保持向後兼容, re.U 標記依然存在(還有他的同義 re.UNICODE 和嵌入形式 (?u) ) , 可是這些在 Python 3 是冗餘的,由於默認字符串已是Unicode了(而且Unicode匹配不容許byte出現)。

re. DEBUG

顯示編譯時的debug信息,沒有內聯標記。

re. I
re. IGNORECASE

進行忽略大小寫匹配;表達式如 [A-Z] 也會匹配小寫字符。Unicode匹配(好比 Ü 匹配 ü)一樣有用,除非設置了 re.ASCII 標記來禁用非ASCII匹配。當前語言區域不會改變這個標記,除非設置了 re.LOCALE 標記。這個至關於內聯標記 (?i) 。

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

re. L
re. LOCALE

由當前語言區域決定 \w\W\b\B 和大小寫敏感匹配。這個標記只能對byte樣式有效。這個標記不推薦使用,由於語言區域機制很不可靠,它一次只能處理一個 "習慣」,並且只對8位字節有效。Unicode匹配在Python 3 裏默認啓用,並能夠處理不一樣語言。 這個對應內聯標記 (?L) 。

在 3.6 版更改: re.LOCALE 只能用於byte樣式,並且不能和 re.ASCII 一塊兒用。

在 3.7 版更改: 設置了 re.LOCALE 標記的編譯正則對象再也不在編譯時依賴語言區域設置。語言區域設置只在匹配的時候影響其結果。

re. M
re. MULTILINE

設置之後,樣式字符 '^' 匹配字符串的開始,和每一行的開始(換行符後面緊跟的符號);樣式字符 '$' 匹配字符串尾,和每一行的結尾(換行符前面那個符號)。默認狀況下,’^’ 匹配字符串頭,'$' 匹配字符串尾。對應內聯標記 (?m) 。

re. S
re. DOTALL

讓 '.' 特殊字符匹配任何字符,包括換行符;若是沒有這個標記,'.' 就匹配 除了 換行符的其餘任意字符。對應內聯標記 (?s) 。

re. X
re. VERBOSE

這個標記容許你編寫更具可讀性更友好的正則表達式。經過分段和添加註釋。空白符號會被忽略,除非在一個字符集合當中或者由反斜槓轉義,或者在 *?(?: or (?P<…> 分組以內。當一個行內有 # 不在字符集和轉義序列,那麼它以後的全部字符都是註釋。

意思就是下面兩個正則表達式等價地匹配一個十進制數字:

a = re.compile(r"""\d + # the integral part  \. # the decimal point  \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*") 

對應內聯標記 (?x) 。

re. search (patternstringflags=0)

掃描整個 字符串 找到匹配樣式的第一個位置,並返回一個相應的 匹配對象。若是沒有匹配,就返回一個 None ; 注意這和找到一個零長度匹配是不一樣的。

re. match (patternstringflags=0)

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

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

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

re. fullmatch (patternstringflags=0)

若是整個 string 匹配到正則表達式樣式,就返回一個相應的 匹配對象 。 不然就返回一個 None ;注意這跟零長度匹配是不一樣的。

3.4 新版功能.

re. split (patternstringmaxsplit=0flags=0)

用 pattern 分開 string 。 若是在 pattern 中捕獲到括號,那麼全部的組裏的文字也會包含在列表裏。若是 maxsplit 非零, 最多進行 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'] 

若是分隔符裏有捕獲組合,而且匹配到字符串的開始,那麼結果將會以一個空字符串開始。對於結尾也是同樣

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

這樣的話,分隔組將會出如今結果列表中一樣的位置。

樣式的空匹配將分開字符串,但只在不相臨的情況生效。

>>> 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 版更改: 增長了可選標記參數。

在 3.7 版更改: 增長了空字符串的樣式分隔。

re. findall (patternstringflags=0)

對 string 返回一個不重複的 pattern 的匹配列表, string 從左到右進行掃描,匹配按找到的順序返回。若是樣式裏存在一到多個組,就返回一個組合列表;就是一個元組的列表(若是樣式裏有超過一個組合的話)。空匹配也會包含在結果裏。

在 3.7 版更改: 非空匹配如今能夠在前一個空匹配以後出現了。

re. finditer (patternstringflags=0)

pattern 在 string 裏全部的非重複匹配,返回爲一個迭代器 iterator 保存了 匹配對象 。 string 從左到右掃描,匹配按順序排列。空匹配也包含在結果裏。

在 3.7 版更改: 非空匹配如今能夠在前一個空匹配以後出現了。

re. sub (patternreplstringcount=0flags=0)

返回經過使用 repl 替換在 string 最左邊非重疊出現的 pattern 而得到的字符串。 若是樣式沒有找到,則不加改變地返回 string。 repl 能夠是字符串或函數;如爲字符串,則其中任何反斜槓轉義序列都會被處理。 也就是說,\n 會被轉換爲一個換行符,\r 會被轉換爲一個回車附,依此類推。 未知的 ASCII 字符轉義序列保留在將來使用,會被看成錯誤來處理。 其餘未知轉義序列例如 \& 會保持原樣。 向後引用像是 \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 是一個函數,那它會對每一個非重複的 pattern 的狀況調用。這個函數只能有一個 匹配對象 參數,並返回一個替換後的字符串。好比

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

樣式能夠是一個字符串或者一個 樣式對象 。

可選參數 count 是要替換的最大次數;count 必須是非負整數。若是忽略這個參數,或者設置爲0,全部的匹配都會被替換。空匹配只在不相臨連續的狀況被更替,因此 sub('x*', '-', 'abxd') 返回 '-a-b--d-' 。

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

在 3.1 版更改: 增長了可選標記參數。

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

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

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

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

re. subn (patternreplstringcount=0flags=0)

行爲與 sub() 相同,可是返回一個元組 (字符串, 替換次數).

在 3.1 版更改: 增長了可選標記參數。

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

re. escape (pattern)

轉義 pattern 中的特殊字符。若是你想對任意可能包含正則表達式元字符的文本字符串進行匹配,它就是有用的。好比

>>>
>>> print(re.escape('http://www.python.org')) http://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)))) /|\-|\+|\*\*|\* 

這個函數不能被用於 sub() 和 subn() 的替換字符串,只有反斜槓應該被轉義。 例如:

>>>
>>> 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 版更改: '_' 再也不被轉義。

在 3.7 版更改: 只有在正則表達式中具備特殊含義的字符纔會被轉義。 所以, '!''"''%'"'"',''/'':'';''<''=''>''@' 和 "`" 將再也不會被轉義。

re. purge ()

清除正則表達式緩存。

exception  re. error (msgpattern=Nonepos=None)

raise 一個例外。當傳遞到函數的字符串不是一個有效正則表達式的時候(好比,包含一個不匹配的括號)或者其餘錯誤在編譯時或匹配時產生。若是字符串不包含樣式匹配,是不會被視爲錯誤的。錯誤實例有如下附加屬性:

msg

未格式化的錯誤消息。

pattern

正則表達式樣式。

pos

編譯失敗的 pattern 的位置索引(能夠是 None )。

lineno

對應 pos (能夠是 None) 的行號。

colno

對應 pos (能夠是 None) 的列號。

在 3.5 版更改: 添加了附加屬性。

正則表達式對象 (正則對象)

編譯後的正則表達式對象支持一下方法和屬性:

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

掃描整個 string 尋找第一個匹配的位置, 並返回一個相應的 匹配對象。若是沒有匹配,就返回 None ;注意它和零長度匹配是不一樣的。

可選的第二個參數 pos 給出了字符串中開始搜索的位置索引;默認爲 0,它不徹底等價於字符串切片; '^' 樣式字符匹配字符串真正的開頭,和換行符後面的第一個字符,但不會匹配索引規定開始的位置。

可選參數 endpos 限定了字符串搜索的結束;它假定字符串長度到 endpos , 因此只有從 pos 到 endpos 1 的字符會被匹配。若是 endpos 小於 pos,就不會有匹配產生;另外,若是 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 的 開始位置 可以找到這個正則樣式的任意個匹配,就返回一個相應的 匹配對象。若是不匹配,就返回 None ;注意它與零長度匹配是不一樣的。

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

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

若是整個 string 匹配這個正則表達式,就返回一個相應的 匹配對象 。 不然就返回 None ; 注意跟零長度匹配是不一樣的。

可選參數 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. split (stringmaxsplit=0)

等價於 split() 函數,使用了編譯後的樣式。

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

相似函數 findall() , 使用了編譯後樣式,但也能夠接收可選參數 pos 和 endpos ,限制搜索範圍,就像 search()

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

相似函數 finiter() , 使用了編譯後樣式,但也能夠接收可選參數 pos 和 endpos ,限制搜索範圍,就像 search()

Pattern. sub (replstringcount=0)

等價於 sub() 函數,使用了編譯後的樣式。

Pattern. subn (replstringcount=0)

等價於 subn() 函數,使用了編譯後的樣式。

Pattern. flags

正則匹配標記。這是能夠傳遞給 compile() 的參數,任何 (?…) 內聯標記,隱性標記好比 UNICODE 的結合。

Pattern. groups

捕獲組合的數量。

Pattern. groupindex

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

Pattern. pattern

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

在 3.7 版更改: 添加 copy.copy() 和 copy.deepcopy() 函數的支持。編譯後的正則表達式對象被認爲是原子性的。

匹配對象

匹配對象老是有一個布爾值 True。若是沒有匹配的話 match() 和 search() 返回 None 因此你能夠簡單的用 if 語句來判斷是否匹配

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

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

Match. expand (template)

對 template 進行反斜槓轉義替換而且返回,就像 sub() 方法中同樣。轉義如同 \n 被轉換成合適的字符,數字引用(\1\2)和命名組合(\g<1>\g<name>) 替換爲相應組合的內容。

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

Match. group ([group1...])

返回一個或者多個匹配的子組。若是隻有一個參數,結果就是一個字符串,若是有多個參數,結果就是一個元組(每一個參數對應一個項),若是沒有參數,組1默認到0(整個匹配都被返回)。 若是一個組N 參數值爲 0,相應的返回值就是整個匹配字符串;若是它是一個範圍 [1..99],結果就是相應的括號組字符串。若是一個組號是負數,或者大於樣式中定義的組數,一個 IndexError 索引錯誤就 raise。若是一個組包含在樣式的一部分,並被匹配屢次,就返回最後一個匹配。:

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

若是正則表達式使用了 (?P<name>…) 語法, groupN 參數就也多是命名組合的名字。若是一個字符串參數在樣式中未定義爲組合名,一個 IndexError 就 raise

一個相對複雜的例子

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

返回一個元組,包含全部匹配的子組,在樣式中出現的從1到任意多的組合。 default 參數用於不參與匹配的狀況,默認爲 None

例如

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

若是咱們使小數點可選,那麼不是全部的組都會參與到匹配當中。這些組合默認會返回一個 None ,除非指定了 default 參數。

>>>
>>> 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 參數用於不參與匹配的組合;默認爲 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 匹配到的字串的開始和結束標號。group 默認爲0(意思是整個匹配的子串)。若是 group 存在,但未產生匹配,就返回 -1 。對於一個匹配對象 m, 和一個未參與匹配的組 g ,組 g (等價於 m.group(g))產生的匹配是

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

注意 m.start(group) 將會等於 m.end(group) ,若是 group 匹配一個空字符串的話。好比,在 re.search('b(c?)', 'cba') 以後,m.start(0) 爲 1, m.end(0) 爲 2, m.start(1) 和 m.end(1) 都是 2, m.start(2) raise 一個 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 默認爲0,就是整個匹配。

Match. pos

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

Match. endpos

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

Match. lastindex

捕獲組的最後一個匹配的整數索引值,或者 None 若是沒有匹配產生的話。好比,對於字符串 'ab',表達式 (a)b((a)(b)), 和 ((ab)) 將獲得 lastindex == 1 , 而 (a)(b) 會獲得 lastindex == 2 。

Match. lastgroup

最後一個匹配的命名組名字,或者 None 若是沒有產生匹配的話。

Match. re

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

Match. string

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

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

正則表達式例子

檢查對子

在這個例子裏,咱們使用如下輔助函數來更好地顯示匹配對象:

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

假設你在寫一個撲克程序,一個玩家的一手牌爲五個字符的串,每一個字符表示一張牌,"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" ,包含了一個對子,或者兩張一樣數值的牌。要用正則表達式匹配它,應該使用向後引用以下

>>>
>>> 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',)>" 

要找出對子由什麼牌組成,開發者能夠按照下面的方式來使用匹配對象的 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函數 scanf() 的替代品。正則表達式一般比 scanf() 格式字符串要更強大一些,但也帶來更多複雜性。下面的表格提供了 scanf() 格式符和正則表達式大體相同的映射。

scanf() 格式符

正則表達式

%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]+

從文件名和數字提取字符串

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

你可使用 scanf() 格式化

%s - %d errors, %d warnings 

等價的正則表達式是:

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

search() vs. match()

Python 提供了兩種不一樣的操做:基於 re.match() 檢查字符串開頭,或者 re.search() 檢查字符串的任意位置(默認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 多行模式中函數 match() 只匹配字符串的開始,但使用 search() 和以 '^' 開始的正則表達式會匹配每行的開始

>>>
>>> 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() 將字符串用參數傳遞的樣式分隔開。這個方法對於轉換文本數據到易讀並且容易修改的數據結構,是頗有用的,以下面的例子證實。

首先,這裏是輸入。 它一般來自一個文件,這裏咱們使用三重引號字符串語法

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

條目用一個或者多個換行符分開。如今咱們將字符串轉換爲一個列表,每一個非空行都有一個條目:

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

最終,將每一個條目分割爲一個由名字、姓氏、電話號碼和地址組成的列表。咱們爲 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']] 

:? 樣式匹配姓後面的冒號,所以它不出如今結果列表中。若是 maxsplit 設置爲 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() 替換字符串中出現的樣式的每個實例。這個例子證實了使用 sub() 來整理文字,或者隨機化每一個字符的位置,除了首位和末尾字符

>>>
>>> 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() 匹配樣式 全部 的出現,不只是像 search() 中的第一個匹配。好比,若是一個做者但願找到文字中的全部副詞,他可能會按照如下方法用 findall()

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

找到全部副詞和位置

若是須要匹配樣式的更多信息, finditer() 能夠起到做用,它提供了 匹配對象 做爲返回值,而不是字符串。繼續上面的例子,若是一個做者但願找到全部副詞和它的位置,能夠按照下面方法使用 finditer()

>>>
>>> text = "He was carefully disguised but captured quickly by police." >>> for m in re.finditer(r"\w+ly", text): ... print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0))) 07-16: carefully 40-47: quickly 

原始字符記法

原始字符串記法 (r"text") 保持正則表達式正常。不然,每一個正則式裏的反斜槓('\') 都必須前綴一個反斜槓來轉義。好比,下面兩行代碼功能就是徹底一致的

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

當須要匹配一個字符反斜槓,它必須在正則表達式中轉義。在原始字符串記法,就是 r"\\"。不然就必須用 "\\\\",來表示一樣的意思

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

寫一個詞法分析器

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

文字目錄是由正則表達式指定的。這個技術是經過將這些樣式合併爲一個主正則式,而且循環匹配來實現的

import collections import re Token = collections.namedtuple('Token', ['type', 'value', 'line', 'column']) 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) 

這個詞法器產生如下輸出

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)


總結

 

 

 

 

經常使用正則表達式

用戶名 /^[a-z0-9_-]{3,16}$/
密碼 /^[a-z0-9_-]{6,18}$/
十六進制值 /^#?([a-f0-9]{6}|[a-f0-9]{3})$/
電子郵箱 /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
/^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/
URL /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
IP 地址 /((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
HTML 標籤 /^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/
刪除代碼\\註釋 (?<!http:|\S)//.*$
Unicode編碼中的漢字範圍 /^[\u2E80-\u9FFF]+$/
相關文章
相關標籤/搜索