上一篇文章: Python標準庫---1八、文本處理服務:string 常見的字符串操做
下一篇文章:
這個模塊提供了與 Perl 語言相似的正則表達式匹配操做。python
模式和被搜索的字符串既能夠是 Unicode 字符串 (str) ,也能夠是8位字節串 (bytes)。 可是,Unicode 字符串與8位字節串不能混用:也就是說,你不能用一個字節串模式去匹配 Unicode 字符串,反之亦然;相似地,當進行替換操做時,替換字符串的類型也必須與所用的模式和搜索字符串的類型一致。git
正則表達式使用反斜槓('')來表示特殊形式,或者把特殊字符轉義成普通字符。 而反斜槓在普通的 Python 字符串裏也有相同的做用,因此就產生了衝突。好比說,要匹配一個字面上的反斜槓,正則表達式模式不得不寫成 '\\',由於正則表達式裏匹配一個反斜槓必須是 \ ,而每一個反斜槓在普通的 Python 字符串裏都要寫成 \ 。正則表達式
解決辦法是對於正則表達式樣式使用 Python 的原始字符串表示法;在帶有 'r' 前綴的字符串字面值中,反斜槓沒必要作任何特殊處理。 所以 r"n" 表示包含 '' 和 'n' 兩個字符的字符串,而 "n" 則表示只包含一個換行符的字符串。 樣式在 Python 代碼中一般都會使用這種原始字符串表示法來表示。shell
絕大部分正則表達式操做都提供爲模塊函數和方法,在 編譯正則表達式. 這些函數是一個捷徑,不須要先編譯一個正則對象,可是損失了一些優化參數。segmentfault
參見第三方模塊 regex , 提供了與標準庫 re 模塊兼容的API接口, 同時還提供了額外的功能和更全面的Unicode支持。緩存
一個正則表達式(或RE)指定了一集與之匹配的字符串;模塊內的函數可讓你檢查某個字符串是否跟給定的正則表達式匹配(或者一個正則表達式是否匹配到一個字符串,這兩種說法含義相同)。數據結構
正則表達式能夠拼接; 若是 A 和 B 都是正則表達式, 那麼 AB 也是正則表達式。 一般, 若是字符串 p 匹配 A 而且另外一個字符串 q 匹配 B, 那麼 pq 能夠匹配 AB。除非 A 或者 B 包含低優先級操做,A 和 B 存在邊界條件;或者命名組引用。因此,複雜表達式能夠很容易的從這裏描述的簡單源語表達式構建。 瞭解更多正則表達式理論和實現,參考the Friedl book [Frie09] ,或者其餘編譯器構建的書籍。dom
如下是正則表達式格式的簡要說明。更詳細的信息和演示,參考 正則表達式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' ;在 'foon' 搜索 $ 會找到兩個空串:一個在換行前,一個在字符串最後。
對它前面的正則式匹配0到任意次重複, 儘可能多的匹配字符串。 ab* 會匹配 'a', 'ab', 或者 'a'後面跟隨任意個
'b'。
對它前面的正則式匹配1到任意次重複。 ab+ 會匹配 'a' 後面跟隨1個以上到任意個 'b',它不會匹配 'a'。
對它前面的正則式匹配0到1次重複。 ab? 會匹配 'a' 或者 'ab'。
'', '+',和 '?' 修飾符都是 貪婪的;它們在字符串進行儘量多的匹配。有時候並不須要這種行爲。若是正則式 <.> 但願找到 ' b <c>',它將會匹配整個字符串,而不只是 ''。在修飾符以後添加 ? 將使樣式以 非貪婪方式或者 :dfn:
最小 方式進行匹配; 儘可能 少 的字符將會被匹配。 使用正則式 <.*?> 將會僅僅匹配 ''。
對其以前的正則式指定匹配 m 個重複;少於 m 的話就會致使匹配失敗。好比, a{6} 將匹配6個 'a' , 可是不能是5個。
對正則式進行 m 到 n 次匹配,在 m 和 n 之間取儘可能多。 好比,a{3,5} 將匹配 3 到 5個 'a'。忽略 m 意爲指定下界爲0,忽略 n 指定上界爲無限次。 好比 a{4,}b 將匹配 'aaaab' 或者1000個 'a' 尾隨一個 'b',但不能匹配 'aaab'。逗號不能省略,不然沒法辨別修飾符應該忽略哪一個邊界。
前一個修飾符的非貪婪模式,只匹配儘可能少的字符次數。好比,對於 '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>...) 是惟一的例外。 如下是目前支持的擴展。
( '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 參數。標記應該在表達式字符串首位表示。
正則括號的非捕獲版本。 匹配在括號內的任何正則表達式,但該分組所匹配的子字符串 不能 在執行匹配後被獲取或是以後在模式中被引用。
('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' 一樣能夠用在一個組合內。
(命名組合)相似正則組合,可是匹配到的子串組在外部是經過定義的 name 來獲取的。組合名必須是有效的Python標識符,而且每一個組合名只能用一個正則表達式定義,只能定義一次。一個符號組合一樣是一個數字組合,就像這個組合沒有被命名同樣。
命名組合能夠在三種上下文中引用。若是樣式是 (?P<quote>['"]).*?(?P=quote) (也就是說,匹配單引號或者雙引號括起來的字符串):
反向引用一個命名組合;它匹配前面那個叫 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,no-pattern 可選,也能夠被忽略。好比, (<)?(w+@w+(?:.w+)+)(?(1)>|$) 是一個email樣式匹配,將匹配 '<user@host.com>' 或 'user@host.com' ,但不會匹配 '<user@host.com' ,也不會匹配 'user@host.com>'。
由 '' 和一個字符組成的特殊序列在如下列出。 若是普通字符不是ASCII數位或者ASCII字母,那麼正則樣式將匹配第二個字符。好比,$ 匹配字符 '$'.
匹配數字表明的組合。每一個括號是一個組合,組合從1開始編號。好比 (.+) 1 匹配 'the the' 或者 '55 55', 但不會匹配 'thethe' (注意組合後面的空格)。這個特殊序列只能用於匹配前面99個組合。若是 number 的第一個數位是0, 或者 number 是三個八進制數,它將不會被看做是一個組合,而是八進制的數字值。在 '[' 和 ']' 字符集合內,任何數字轉義都被看做是字符。
只匹配字符串開始。
匹配空字符串,但只在單詞開始或結尾的位置。一個單詞被定義爲一個單詞字符的序列。注意,一般 b 定義爲 w 和 W 字符之間,或者 w 和字符串開始/結尾的邊界, 意思就是 r'bfoob' 匹配 'foo', 'foo.', '(foo)', 'bar foo baz' 但不匹配 'foobar' 或者 'foo3'。
默認狀況下,Unicode字母和數字是在Unicode樣式中使用的,可是能夠用 ASCII 標記來更改。若是 LOCALE 標記被設置的話,詞的邊界是由當前語言區域設置決定的,b 表示退格字符,以便與Python字符串文本兼容。
匹配空字符串,但 不 能在詞的開頭或者結尾。意思就是 r'pyB' 匹配 'python', 'py3', 'py2', 但不匹配 'py', 'py.', 或者 'py!'. B 是 b 的取非,因此Unicode樣式的詞語是由Unicode字母,數字或下劃線構成的,雖然能夠用 ASCII 標誌來改變。若是使用了 LOCALE 標誌,則詞的邊界由當前語言區域設置。
對於 Unicode (str) 樣式:
匹配任何Unicode十進制數(就是在Unicode字符目錄[Nd]裏的字符)。這包括了 [0-9] ,和不少其餘的數字字符。若是設置了 ASCII 標誌,就只匹配 [0-9] 。
對於8位(bytes)樣式: 匹配任何十進制數,就是 [0-9]。
匹配任何非十進制數字的字符。就是 d 取非。 若是設置了 ASCII 標誌,就至關於 1 。
對於 Unicode (str) 樣式: 匹配任何Unicode空白字符(包括 [ tnrfv] ,還有不少其餘字符,好比不一樣語言排版規則約定的不換行空格)。若是 ASCII 被設置,就只匹配 [ tnrfv] 。
對於8位(bytes)樣式: 匹配ASCII中的空白字符,就是 [ tnrfv] 。
匹配任何非空白字符。就是 s 取非。若是設置了 ASCII 標誌,就至關於 2 。
對於 Unicode (str) 樣式:匹配Unicode詞語的字符,包含了能夠構成詞語的絕大部分字符,也包括數字和下劃線。若是設置了 ASCII 標誌,就只匹配 [a-zA-Z0-9_] 。
對於8位(bytes)樣式:匹配ASCII字符中的數字和字母和下劃線,就是 [a-zA-Z0-9_] 。若是設置了 LOCALE 標記,就匹配當前語言區域的數字和字母和下劃線。
匹配任何非詞語字符。是 w 取非。若是設置了 ASCII 標記,就至關於 3 。若是設置了 LOCALE 標誌,就匹配當前語言區域的 非 詞語字符。
只匹配字符串尾。
絕大部分Python的標準轉義字符也被正則表達式分析器支持。:
\a \b \f \n \r \t \u \U \v \x \\
(注意 b 被用於表示詞語的邊界,它只在字符集合內表示退格,好比 [b] 。)
'u' 和 'U' 轉義序列只在 Unicode 樣式中支持。 在 bytes 算啊看會顯示錯誤。 未知的 ASCII 字符轉義序列保留在將來使用,會被看成錯誤來處理。
八進制轉義包含爲一個有限形式。若是首位數字是 0, 或者有三個八進制數位,那麼就認爲它是八進制轉義。其餘的狀況,就看做是組引用。對於字符串文本,八進制轉義最多有三個數位長。
在 3.3 版更改: 增長了 'u' 和 'U' 轉義序列。
在 3.6 版更改: 由 '' 和一個ASCII字符組成的未知轉義會被當作錯誤。
模塊定義了幾個函數,常量,和一個例外。有些函數是編譯後的正則表達式方法的簡化版本(少了一些特性)。絕大部分重要的應用,老是會先將正則表達式編譯,以後在進行操做。
在 3.6 版更改: 標誌常量如今是 RegexFlag 類的實例,這個類是 enum.IntFlag 的子類。
將正則表達式的樣式編譯爲一個 正則表達式對象 (正則對象),能夠用於匹配,經過這個對象的方法 match(), search() 以及其餘以下描述。
這個表達式的行爲能夠經過指定 標記 的值來改變。值能夠是如下任意變量,能夠經過位的OR操做來結合( | 操做符)。
序列
prog = re.compile(pattern) result = prog.match(string)
等價於
result = re.match(pattern, string)
若是須要屢次使用這個正則表達式的話,使用 re.compile() 和保存這個正則對象以便複用,可讓程序更加高效。
註解
經過 re.compile() 編譯後的樣式,和模塊級的函數會被緩存, 因此少數的正則表達式使用無需考慮編譯的問題。
讓 w, W, b, B, d, D, s 和 S 只匹配ASCII,而不是Unicode。這隻對Unicode樣式有效,會被byte樣式忽略。至關於前面語法中的內聯標誌 (?a) 。
注意,爲了保持向後兼容, re.U 標記依然存在(還有他的同義 re.UNICODE 和嵌入形式 (?u) ) , 可是這些在 Python 3 是冗餘的,由於默認字符串已是Unicode了(而且Unicode匹配不容許byte出現)。
顯示編譯時的debug信息,沒有內聯標記。
進行忽略大小寫匹配;表達式如 [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' 。
由當前語言區域決定 w, W, b, B 和大小寫敏感匹配。這個標記只能對byte樣式有效。這個標記不推薦使用,由於語言區域機制很不可靠,它一次只能處理一個 "習慣」,並且只對8位字節有效。Unicode匹配在Python 3 裏默認啓用,並能夠處理不一樣語言。 這個對應內聯標記 (?L) 。
在 3.6 版更改: re.LOCALE 只能用於byte樣式,並且不能和 re.ASCII 一塊兒用。
在 3.7 版更改: 設置了 re.LOCALE 標記的編譯正則對象再也不在編譯時依賴語言區域設置。語言區域設置只在匹配的時候影響其結果。
設置之後,樣式字符 '^' 匹配字符串的開始,和每一行的開始(換行符後面緊跟的符號);樣式字符 '$' 匹配字符串尾,和每一行的結尾(換行符前面那個符號)。默認狀況下,’^’ 匹配字符串頭,'$' 匹配字符串尾。對應內聯標記 (?m) 。
讓 '.' 特殊字符匹配任何字符,包括換行符;若是沒有這個標記,'.' 就匹配 除了 換行符的其餘任意字符。對應內聯標記 (?s) 。
這個標記容許你編寫更具可讀性更友好的正則表達式。經過分段和添加註釋。空白符號會被忽略,除非在一個字符集合當中或者由反斜槓轉義,或者在 *?, (?: 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(pattern, string, flags=0)
掃描整個 字符串 找到匹配樣式的第一個位置,並返回一個相應的 匹配對象。若是沒有匹配,就返回一個 None ; 注意這和找到一個零長度匹配是不一樣的。
若是 string 開始的0或者多個字符匹配到了正則表達式樣式,就返回一個相應的 匹配對象 。 若是沒有匹配,就返回 None ;注意它跟零長度匹配是不一樣的。
注意即使是 MULTILINE 多行模式, re.match() 也只匹配字符串的開始位置,而不匹配每行開始。
若是你想定位 string 的任何位置,使用 search() 來替代(也可參考 search() vs. match() )
若是整個 string 匹配到正則表達式樣式,就返回一個相應的 匹配對象 。 不然就返回一個 None ;注意這跟零長度匹配是不一樣的。
3.4 新版功能.
用 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 版更改: 增長了空字符串的樣式分隔。
對 string 返回一個不重複的 pattern 的匹配列表, string 從左到右進行掃描,匹配按找到的順序返回。若是樣式裏存在一到多個組,就返回一個組合列表;就是一個元組的列表(若是樣式裏有超過一個組合的話)。空匹配也會包含在結果裏。
在 3.7 版更改: 非空匹配如今能夠在前一個空匹配以後出現了。
pattern 在 string 裏全部的非重複匹配,返回爲一個迭代器 iterator 保存了 匹配對象 。 string 從左到右掃描,匹配按順序排列。空匹配也包含在結果裏。
在 3.7 版更改: 非空匹配如今能夠在前一個空匹配以後出現了。
返回經過使用 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 版更改: 樣式中的空匹配相鄰接時會被替換。
在 3.5 版更改: 不匹配的組合替換爲空字符串。
轉義 pattern 中的特殊字符。若是你想對任意可能包含正則表達式元字符的文本字符串進行匹配,它就是有用的。好比
>>> print(re.escape('python.exe')) python\.exe >>> 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 版更改: 只有在正則表達式中能夠產生特殊含義的字符會被轉義。
清除正則表達式緩存。
raise 一個例外。當傳遞到函數的字符串不是一個有效正則表達式的時候(好比,包含一個不匹配的括號)或者其餘錯誤在編譯時或匹配時產生。若是字符串不包含樣式匹配,是不會被視爲錯誤的。錯誤實例有如下附加屬性:
msg 未格式化的錯誤消息。 pattern 正則表達式樣式。 pos 編譯失敗的 pattern 的位置索引(能夠是 None )。 lineno 對應 pos (能夠是 None) 的行號。 colno 對應 pos (能夠是 None) 的列號。
在 3.5 版更改: 添加了附加屬性。
編譯後的正則表達式對象支持一下方法和屬性:
掃描整個 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"
若是 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())。
若是整個 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 新版功能.
等價於 split() 函數,使用了編譯後的樣式。
相似函數 findall() , 使用了編譯後樣式,但也能夠接收可選參數 pos 和 endpos ,限制搜索範圍,就像 search()。
相似函數 finiter() , 使用了編譯後樣式,但也能夠接收可選參數 pos 和 endpos ,限制搜索範圍,就像 search()。
等價於 sub() 函數,使用了編譯後的樣式。
等價於 subn() 函數,使用了編譯後的樣式。
正則匹配標記。這是能夠傳遞給 compile() 的參數,任何 (?…) 內聯標記,隱性標記好比 UNICODE 的結合。
捕獲組合的數量。
映射由 (?P<id>) 定義的命名符號組合和數字組合的字典。若是沒有符號組,那字典就是空的。
編譯對象的原始樣式字符串。
在 3.7 版更改: 添加 copy.copy() 和 copy.deepcopy() 函數的支持。編譯後的正則表達式對象被認爲是原子性的。
匹配對象老是有一個布爾值 True。若是沒有匹配的話 match() 和 search() 返回 None 因此你能夠簡單的用 if 語句來判斷是否匹配
match = re.search(pattern, string) if match: process(match)
匹配對象支持如下方法和屬性:
對 template 進行反斜槓轉義替換而且返回,就像 sub() 方法中同樣。轉義如同 n 被轉換成合適的字符,數字引用(1, 2)和命名組合(g<1>, g<name>) 替換爲相應組合的內容。
在 3.5 版更改: 不匹配的組合替換爲空字符串。
返回一個或者多個匹配的子組。若是隻有一個參數,結果就是一個字符串,若是有多個參數,結果就是一個元組(每一個參數對應一個項),若是沒有參數,組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'
這個等價於 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 新版功能.
返回一個元組,包含全部匹配的子組,在樣式中出現的從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')
返回一個字典,包含了全部的 命名 子組。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'}
返回 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 匹配一個空字符串的話。好比,在 m = 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'
對於一個匹配 m , 返回一個二元組 (m.start(group), m.end(group)) 。 注意若是 group 沒有在這個匹配中,就返回 (-1, -1) 。group 默認爲0,就是整個匹配。
pos 的值,會傳遞給 search() 或 match() 的方法 a 正則對象 。這個是正則引擎開始在字符串搜索一個匹配的索引位置。
endpos 的值,會傳遞給 search() 或 match() 的方法 a 正則對象 。這個是正則引擎中止在字符串搜索一個匹配的索引位置。
捕獲組的最後一個匹配的整數索引值,或者 None 若是沒有匹配產生的話。好比,對於字符串 'ab',表達式 (a)b, ((a)(b)), 和 ((ab)) 將獲得 lastindex == 1 , 而 (a)(b) 會獲得 lastindex == 2 。
最後一個匹配的命名組名字,或者 None 若是沒有產生匹配的話。
返回產生這個實例的 正則對象 , 這個實例是由 正則對象的 match() 或 search() 方法產生的。
傳遞到 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.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'
Python 目前沒有一個相似c函數 scanf() 的替代品。正則表達式一般比 scanf() 格式字符串要更強大一些,但也帶來更多複雜性。下面的表格提供了 scanf() 格式符和正則表達式大體相同的映射。
從文件名和數字提取字符串
/usr/sbin/sendmail - 0 errors, 4 warnings
你可使用 scanf() 格式化
%s - %d errors, %d warnings
等價的正則表達式是:
(\S+) - (\d+) errors, (\d+) warnings
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)
Frie09
Friedl, Jeffrey. Mastering Regular Expressions. 第三版, O’Reilly Media, 2009. 第三版再也不使用Python, 但初版提供了編寫正則表達式的良好細節。