re --- 正規表示式 (regular expression) 操作¶
原始碼:Lib/re/
此模組提供類似於 Perl 中正規表示式的匹配操作。
被搜尋的模式 (pattern) 與字串可以是 Unicode 字串 (str),也可以是 8-bit 字串 (bytes)。然而,Unicode 字串和 8-bit 字串不能混用:也就是,你不能用 byte 模式匹配 Unicode 字串,反之亦然;同樣地,替換時,用來替換的字串必須與模式和搜尋字串是相同的型別 (type)。
正規表示式使用反斜線字元 ('\') 表示特別的形式,或是使用特殊字元而不觸發它們的特殊意義。這與 Python 在字串文本 (literal) 中,為了相同目的使用同一個字元的做法相衝突;舉例來說,為了匹配一個反斜線字面值,可能需要寫'\\\\' 當作模式字串,因為正規表示式必須是\\,而且每個反斜線在一個普通的 Python 字串文本中必須表示為\\。另外,請注意在 Python 的字串文本中使用反斜線的任何無效跳脫序列目前會產生一個SyntaxWarning,而在未來這會變成一個SyntaxError。儘管它對正規表示式是一個有效的跳脫序列,這種行為也會發生。
解決方法是對正規表示式模式使用 Python 的原始字串符號;反斜線在一個以'r' 為前綴的字串文本中不會被用任何特別的方式處理。所以r"\n" 是一個兩個字元的字串,包含'\' 和'n',同時"\n" 是一個單個字元的字串,包含一個換行符號。通常模式在 Python 程式中會使用這個原始字串符號表示。
請務必注意到大部分的正規表示式操作是可以在模組層級的函式和compiled regular expressions 中的方法使用的。這些函式是個捷徑且讓你不需要先編譯一個正規表示式物件,但是會缺少一些微調參數。
正規表示式語法¶
一個正規表示式(或 RE)會指定一組匹配它的字串;這個模組的函式讓你可以檢查一個特定的字串是否匹配給定的正規表示式(或是給定的正規表示式是否匹配特定的字串,說到底是一樣的)。
正規表示式可以被連接 (concatenated) 成新的正規表示式;如果A 和B 都是正規表示式,則AB 也是一個正規表示式。一般來說,如果一個字串p 與A 匹配,並且另一個字串q 與B 匹配,則字串pq 會匹配 AB。或:這在以下情況下不成立:A*或 *B 包含低優先順序的運算子;或A 和B 之間的邊界條件 (boundary conditions);或是有編號群組 (numbered group) 的參照。因此,複雜的正規表示式可以輕鬆地從此處提到的簡單原始正規表示式建立。關於正規表示式的理論和實作,請參考 Friedl 書[Frie09],或任何有關建構編譯器的書籍。
一個簡短的正規表示式格式解釋如下。如需更多資訊或以較平易的方式了解,請參閱如何使用正規表示式。
正規表示式可以包含特殊和一般字元。大多數一般字元,如'A'、'a' 或'0' 是最簡單的正規表示式;它們只匹配它們自己。你可以連接一般字元,讓last 匹配字串'last'。(在本節的其餘部分,我們會用通常沒有引號的這種特殊樣式 來書寫正規表示式,而被匹配的字串會'在單引號中'。)
某些字元是特殊的,像'|' 或'('。特殊字元會代表一般字元的類別,或是會影響它們周圍正規表示式的解讀方法。
重複運算子或量詞 (quantifiers)(*,+,?,{m,n} 等)不能直接嵌套使用。這樣避免了和非貪婪修飾符號後綴? 和其他實作中的修飾符號的模糊性。要在一個重複正規表示式內添加第二個重複,可以使用括號。例如:正規表示式(?:a{6})* 會匹配任何六的倍數個a 字元。
特殊字元包含:
.(點) 在預設模式下,這會匹配除換行符號外的任何字元。如果指定了
DOTALL旗標,這會匹配包含換行符號的任何字元。無論旗標為何,(?s:.)都會匹配任何字元。
^(插入符號) 會匹配字串的開頭,並且在
MULTILINE模式下,也會立即匹配緊接在每個換行符號之後的位置。
$匹配字串的結尾或是字串結尾的換行符號之前,並且在
MULTILINE模式下會匹配換行符號之前的位置。foo會匹配 'foo' 和 'foobar',而正規表示式foo$只會匹配 'foo'。更有趣的是,在'foo1\nfoo2\n'中搜尋foo.$,正常情況下會匹配 'foo2',但是在MULTILINE模式下會匹配 'foo1';在'foo\n'中搜尋單一個$會找到兩個(空的)匹配:一個在換行符號之前,一個在字串結尾。
*使得到的正規表示式匹配前面正規表示式的 0 或多次的重複,盡可能多次的重複。
ab*會匹配 'a'、'ab',或後面跟著任何數量個 'b' 的 'a'。
+使得到的正規表示式匹配前面正規表示式的 1 或多次的重複。
ab+會匹配後面跟著任何非零數量個 'b' 的 'a';它不會匹配 'a'。
?使得到的正規表示式匹配前面正規表示式的 0 或 1 次的重複。
ab?會匹配 'a' 或 'ab'。
*?,+?,??量詞 (quantifier)
'*'、'+'和'?'都是greedy(貪婪的);它們會盡可能地匹配更多文字。有時候這種行為不是預期的;如果正規表示式<.*>被用來匹配'<a>b<c>',它會匹配整個字串,而不只是'<a>'。在量詞後添加?會讓他以non-greedy(非貪婪的)或minimal(最小的)方式進行匹配;盡可能匹配更少的字元。使用正規表示式<.*?>只會匹配到'<a>'。
*+,++,?+類似於量詞
'*'、'+'和'?',添加了'+'的量詞也會盡可能多次的匹配。然而,不同於真正的貪婪量詞,這些量詞在接續的正規表示式匹配失敗時不允許回溯 (back-tracking)。這些量詞被稱為possessive (佔有的)量詞。例如,a*a會匹配'aaaa',因為a*會匹配全部 4 個'a',但是在遇到最後的'a'時,此正規表示式會回溯,以讓a*最終可以總共匹配 3 個'a',而第四個'a'會被最後的'a'匹配。然而,當a*+a被用來匹配'aaaa'時,a*+會匹配全部 4 個'a',但是當最終的'a'在尋找更多字元匹配失敗時,此正規表示式不能回溯並會因此匹配失敗。x*+、x++和x?+分別等同於(?>x*)、(?>x+)和(?>x?)。在 3.11 版被加入.
{m}指定應該恰好匹配m 個前面的正規表示式;太少的匹配會造成整個正規表示式匹配失敗。例如,
a{6}會匹配恰好六個'a'字元,但不匹配五個。{m,n}使得到的正規表示式重複匹配前面的正規表示式m 到n 次,並嘗試盡可能多次的匹配。例如,
a{3,5}會匹配 3 到 5 個'a'字元。忽略m 會指定下限為零,且忽略n 會指定無限大的上限。舉例來說,a{4,}b會匹配'aaaab'或一千個'a'字元加上一個'b',但是不匹配'aaab'。不可以忽略逗號,否則量詞會與前述的形式混淆。{m,n}?使得到的正規表示式重複匹配前面的正規表示式m 到n 次,嘗試盡可能更少次的匹配。這是上一個量詞的非貪婪版本。例如,對六個字元的字串
'aaaaaa',a{3,5}會匹配 5 個'a'字元,而a{3,5}?只會匹配 3 個字元。{m,n}+使得到的正規表示式重複匹配前面的正規表示式m 到n 次,並嘗試盡可能更多次的匹配而不建立任何回溯點。這是上述量詞的佔有版本。例如,對六個字元的字串
'aaaaaa',a{3,5}+aa嘗試匹配 5 個'a'字元,然後需要再 2 個'a',會需要比可用的字元更多所以失敗,而a{3,5}aa會捕捉到 5 個'a',然後回溯成 4 個'a',接著最後兩個'a'會被模式中最後的aa匹配。x{m,n}+等同於(?>x{m,n})。在 3.11 版被加入.
\用來跳脫特殊字元(允許你匹配如
'*'、'?'等字元),或是表示一個特殊序列;特殊序列將在下方討論。如果你沒有使用原始字串來表示正規表示式,請記得 Python 也會使用反斜線作為字串文本的跳脫序列;如果 Python 的剖析器辨認不出該跳脫序列,反斜線和接續的字元將會被包含在得到的字串中。然而,如果 Python 能辨認出該序列,反斜線應該要被重複兩次。這很複雜並且難以理解,所以強烈建議,除了最簡單的正規表示式,都應該使用原始字串。
[]用來表示一個字元集合。在一個集合中:
字元可以獨立列出,例如:
[amk]會匹配'a'、'm'或'k'。
可以透過給定兩個字元並且使用
'-'分隔它們來表示一個範圍的字元,例如[a-z]會匹配任何 ASCII 小寫字母,[0-5][0-9]會匹配所有從00到59的兩位數字,而[0-9A-Fa-f]會匹配任何十六進位數字。如果-被跳脫了(如:[a\-z]) 或是放在第一或最後一個位置(如:[-a]或[a-]),它將會匹配字面的'-'。除反斜線外的特殊字元會在集合內失去它們的特殊意義。例如,
[(+*)]會匹配任何字面字元'('、'+'、'*',或')'。
反斜線可能用於跳脫集合內具有特殊意義的字元,像是
'-'、']'、'^'和'\\'本身,或是表示一個代表單一字元的特殊序列,像是\xa0或\n或一個字元類別,如\w或\S(定義如下)。請注意,\b代表單一個 "backspace" 字元,而不是在集合外代表的字元邊界,且像是\1的數值跳脫總是代表八進位數字的跳脫,而不是群組的參照。不匹配單一字元的特殊序列是不被允許的,像是\A和\Z。
不在範圍內的字元可以透過取集合的補集 (complement) <complementing> 匹配。如果集合中的第一個字元是
'^',所有不在集合內的字元都會被匹配。例如,[^5]會匹配任何除了'5'的字元,而[^^]會匹配任何除了'^'的字元。如果^不是集合中的第一個字元的話,沒有特殊意義。要在集合中匹配字面的
']',在前面加上一個反斜線,或是將它放在集合中的最前面。例如,[()[\]{}]和[]()[{}]都會匹配右方括號、左方括號、花括號和括號。
未來可能會支援Unicode Technical Standard #18 中的嵌套集合與集合操作。這會改變語法,所以為了促進這個改變,暫時會在模糊的情況下引發
FutureWarning。包含了以字面'['開頭,或是包含字面的字元序列'--'、'&&'、'~~'和'||'的集合。為了避免警告,請用反斜線跳脫它們。
在 3.7 版的變更:如果一個字元集合包含了其語義未來會被改變的結構,
FutureWarning會被引發。
|A|B,其中A 和B 可以為任何正規表示式,會創造出一個匹配A 或是B 的正規表示式。任何數量的正規表示式可以像這樣用'|'分隔。這也可以用在群組(見下文)中。當目標字串被掃描時,被'|'分隔的正規表示式會被從左到右嘗試。當一個模式完全匹配時,那條分支就被接受了。這代表一旦A 匹配了,B 就不會被進一步測試,就算它會讓整個匹配更長。換句話說,'|'永遠不是貪婪的。要匹配字面的'|',使用\|,或是將它包圍在一個字元類別中,就像[|]。
(...)匹配括號中的任何正規表示式,並且表示一個群組的開始和結束;群組的內容可以在執行匹配後取得,並且在後續的字串可以使用
\number特殊序列來匹配,如下所述。要匹配字面的'('或')',用\(或\),或是將它們包圍在一個字元類別中:[(、[)]。
(?...)這是一個擴充表示法(否則一個
'?'接著一個'('是沒有意義的)。'?'後面的第一個字元決定了這個結構的意義和進一步的語法。擴充通常不會創造新的群組;(?P<name>...)是這個規則的唯一例外。以下是目前支援的擴充。(?aiLmsux)(集合
'a'、'i'、'L'、'm'、's'、'u'、'x'中的一或多個字母。)該群組會匹配空字串;這些字母會為整個正規表示式設定對應的旗標。(這些旗標在模組內容 中說明。)如果你想將旗標當作正規表示式的一部分,而不是傳遞一個flag 引數給
re.compile()函式的話,這會有幫助。旗標應該首先在正規表示式字串中使用。在 3.11 版的變更:此結構只能用於正規表示式的開頭。
(?:...)一個非捕捉版本的普通括號。匹配括號內的任何正規表示式,但是被群組匹配到的子字串不能在執行匹配後被取得,或是在之後的模式中被參照。
(?aiLmsux-imsx:...)(集合
'a'、'i'、'L'、'm'、's'、'u'、'x'中的零或多個字母,選擇性地接著'-',並接著一或多個'i'、'm'、's'、'x'中的字母。)該字母集合會為那一部分的正規表示式設定或是移除對應的旗標。(這些旗標在模組內容 中說明。)
字母
'a'、'L'和'u'在被當作嵌入旗標時是互斥的,所以它們不能被組合使用或是接在'-'後面。相反地,當它們其中一個出現在嵌入群組時,它會覆蓋括號中群組的匹配模式。在 Unicode 模式中,(?a:...)會切換到僅匹配 ASCII 模式,且(?u:...)會切換到 Unicode 匹配模式(預設)。在位元組模式,(?L:...)會切換到依賴區域設定 (locale) 的匹配,且(?a:...)會切換到僅匹配 ASCII 模式(預設)。這個覆蓋只會在嵌入群組中作用,而原本的匹配模式會在群組外恢復。在 3.6 版被加入.
在 3.7 版的變更:字母
'a'、'L'和'u'也可以被用在群組中。(?>...)嘗試將
...視為獨立的正規表示式進行匹配,且若成功則會繼續匹配後續的模式。如果後續模式匹配失敗,則回溯堆疊 (stack) 只能還原 (unwound) 到(?>...)之前,因為一旦退出了,這個也叫做原子群組 (atomic group) 的正規表示式,已經丟棄了它自己的所有回溯點 (stack point)。因此,(?>.*).永遠不會匹配任何內容,因為.*會先盡可能匹配所有的字元,接著沒有任何剩餘內容可以匹配,導致最終的.匹配失敗。因為原子群組中沒有儲存回溯點,而且群組之前也沒有回溯點,整個正規表示式都會匹配失敗。在 3.11 版被加入.
(?P<name>...)類似於一般的括號,但是這個群組匹配的子字串可以透過符號群組名稱name 存取。群組名稱必須是有效的 Python 識別字 (identifier),並且在
bytes模式中,它們只能包含 ASCII 範圍中的位元組。每個群組名稱在正規表示式中只能定義一次。一個符號群組同時也是一個編號群組,只是等同於該群組沒有名稱。命名群組 (named groups) 可以在三種情境下被參照。如果該模式是
(?P<quote>['"]).*?(?P=quote)(也就是匹配一個用單引號或雙引號包圍的字串):對 "quote" 群組參照的情境
參照方式
在同一個模式中
(?P=quote)(如上例所示)\1
在處理匹配物件m 時
m.group('quote')m.end('quote')(等)
在被當成
re.sub()的repl 引數傳入的字串中\g<quote>\g<1>\1
在 3.12 版的變更:在
bytes模式中,群組的名稱只能包含 ASCII 範圍中的位元組(b'\x00'-b'\x7f')。
(?P=name)對於命名群組的反向參照;它會匹配任何之前被命名為name 的群組所匹配到的文字。
(?#...)一個註解;括號中的內容會被忽略。
(?=...)如果字串接下來可以匹配
...才會成功匹配,但是並不會消耗任何字串。這被稱作lookahead assertion。例如,Isaac(?=Asimov)只在後面跟著'Asimov'時才會匹配'Isaac'。
(?!...)如果字串接下來不匹配
...,才會成功匹配。這是一個負向預查斷言 (negative lookahead assertion) <negative lookahead assertion>。例如,Isaac(?!Asimov)只在後面不跟著'Asimov'時才會匹配'Isaac'。
(?<=...)如果目前位置前方的字串能夠匹配
...,可以成功匹配。這叫做正向回查斷言 (positive lookbehind assertion) <positive lookbehind assertion>。(?<=abc)def會在'abcdef'中找到一個匹配,因為回查會向後 3 個字元,並檢查是否能匹配包含的模式。這個包含的模式只能匹配固定長度的字串,代表abc或a|b是被允許的,但是a*和a{3,4}不被允許。請注意,使用正向回查斷言開頭的模式不會匹配被搜尋字串的開頭;你更可能想要使用search()函式而不是match()函式:>>>importre>>>m=re.search('(?<=abc)def','abcdef')>>>m.group(0)'def'
這個範例在尋找連字號後的單字:
>>>m=re.search(r'(?<=-)\w+','spam-egg')>>>m.group(0)'egg'
在 3.5 版的變更:新增固定長度群組參照的支援。
(?<!...)如果目前位置前方的字串不能夠匹配
...,可以成功匹配。這叫做負向回查斷言 (negative lookbehind assertion) <negative lookbehind assertion>。類似於正向回查斷言,包含的模式只能匹配固定長度的字串。使用負向回查斷言開頭的模式可以匹配被搜尋字串的開頭。
(?(id/name)yes-pattern|no-pattern)如果給定id 或name 的群組存在,會嘗試匹配
yes-pattern,否則會匹配no-pattern。no-pattern是可選的並且可以省略。例如,(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)是一個不好的電子郵件匹配模式,它會匹配'<user@host.com>'和'user@host.com',但不會匹配'<user@host.com'以及'user@host.com>'。在 3.12 版的變更:群組id 只能包含 ASCII 數字。在
bytes模式中,群組name 只能包含 ASCII 範圍中的位元組 (b'\x00'-b'\x7f')。
特殊序列由'\' 和下列清單的一個字元組成。如果序列中的一般字元不是一個 ASCII 數字或是一個 ASCII 字母,那麼產生的的正規表示式會匹配第二個字元。例如,\$ 會匹配字元'$'。
\number匹配相同數字群組中的內容。群組會從 1 開始編號。例如,
(.+)\1會匹配'thethe'或'5555',但不會匹配'thethe'(注意群組後的空格)。這個特殊序列只能用來匹配前 99 個群組之一。如果number 的第一位數是 0,或是number 有 3 個八進位位數,它就不會被解讀成匹配群組,而是解讀成八進位數值number 的字元。在一個字元類別中的'['和']',所有數值的跳脫字元都會被當作字元。
\A只在字串的開頭匹配。
\b匹配空字串,但是只在一個單字的開頭或結尾。一個單字被定義為一個單字字元的序列。請注意在正式情況下,
\b被定義為\w和一個\W字元的邊界(或是反之亦然),或是在\w和字串的開頭或結尾之間。這表示r'\bat\b'會匹配'at'、'at.'、'(at)',以及'asatay',但是不匹配'attempt'或'atlas'。預設的單字字元在 Unicode(字串)模式中,是 Unicode 字母數字 (alphanumerics) 和底線,但是這可以透過使用
ASCII旗標來改變。如果使用了LOCALE旗標,單字的邊界會由目前的區域設定決定。備註
在字元範圍中,為了與 Python 的字串文本的相容性,
\b表示 backspace 字元。
\B匹配空字串,但是只有在空字串不在單字的開頭或結尾時匹配。這表示
r'at\B'會匹配'athens'、'atom'、'attorney',但是不匹配'at'、'at.'或'at!'。\B是\b的相反,所以 Unicode(字串)模式中的單字字元是 Unicode 字母、數字或底線,不過這可以透過使用ASCII旗標來改變。如果使用了LOCALE旗標,單字的邊界會由目前的區域設定決定。在 3.14 版的變更:
\B現在會匹配空的輸入字串。
\d
\D匹配任何不是十進位數字的字元。這是
\d的相反。如果使用了
ASCII旗標,會匹配[^0-9]。
\s- 對於 Unicode(字串)模式:
匹配 Unicode 空格字元(在
str.isspace()中定義)。包含[\t\n\r\f\v],還有許多其他的字元,例如許多語言的排版規則中要求的不換行空格。如果使用了
ASCII旗標,匹配[\t\n\r\f\v]。- 對於 8 位元(位元組)模式:
匹配 ASCII 字元集合中認定的空格;這等同於
[\t\n\r\f\v]。
\S匹配任何不是空格字元的字元。這是
\s的相反。如果使用了
ASCII旗標,匹配[^\t\n\r\f\v]。
\w- 對於 Unicode(字串)模式:
匹配 Unicode 單字字元;這包含全部 Unicode 的字母數字字元(在
str.isalnum()中定義),以及底線 (_)。如果使用了
ASCII旗標,匹配[a-zA-Z0-9_]。- 對於 8 位元(位元組)模式:
匹配在 ASCII 字元集合中被認定為字母或數字的字元;這等同於
[a-zA-Z0-9_]。如果使用了LOCALE旗標,會匹配目前區域設定中被認定為字母或數字的字元,以及底線。
\W匹配任何不是單字字元的字元。這是
\w的相反。預設情況下,會匹配任何不是底線 (_),並且str.isalnum()會回傳False的字元。如果使用了
ASCII旗標,會匹配[^a-zA-Z0-9_]。如果使用了
LOCALE旗標,會匹配目前區域中不是字母數字,也不是底線的字元。
\z只在字串的結尾匹配。
在 3.14 版被加入.
\Z和
\z相同。為了與舊版的 Python 相容而保留。
大多數 Python 的字串文本支援的跳脫序列也能被正規表示式剖析器接受:
\a \b \f \n\N \r \t \u\U \v \x \\
(請注意\b 被用來表示單字邊界,並且只在字元類別內表示 "backspace"。)
'\u'、'\U',和'\N' 跳脫序列只會在 Unicode(字串)模式中可辨認。在位元組模式中,它們是錯誤。未知的跳脫 ASCII 字母被保留於未來使用,並且會被當成錯誤。
八進位數的跳脫被有限地包含在內。如果第一個數字是一個 0,或是如果有三個八進位數字,它就會被當作是一個八進位跳脫。否則,它是一個群組參照。至於字串文本,八進位跳脫最多只能包含三個數字。
在 3.3 版的變更:'\u' 和'\U' 跳脫序列已經被添加。
在 3.6 版的變更:由'\' 和一個 ASCII 字母組成的未知跳脫現在會是錯誤。
在 3.8 版的變更:'\N{name}' 跳脫序列已經被添加。如同字串文本,它會展開成命名的 Unicode 字元(如'\N{EMDASH}')。
模組內容¶
The module defines several functions, constants, and an exception. Some of thefunctions are simplified versions of the full featured methods for compiledregular expressions. Most non-trivial applications always use the compiledform.
旗標¶
在 3.6 版的變更:Flag 常數現在是RegexFlag 的實例,其為enum.IntFlag 的子類別。
- classre.RegexFlag¶
包含下列正規表示式選項的一個
enum.IntFlag類別。在 3.11 版被加入:- added to
__all__
- re.A¶
- re.ASCII¶
使
\w、\W、\b、\B、\d、\D、\s和\S執行僅限 ASCII 的匹配,而不是完整的 Unicode 匹配。這只對 Unicode(字串)模式有意義,並且在位元組模式中會被忽略。對應到內嵌旗標
(?a)。
- re.DEBUG¶
顯示關於已編譯表示式的偵錯資訊。
沒有對應的內嵌旗標。
- re.I¶
- re.IGNORECASE¶
執行不區分大小寫的匹配;像是
[A-Z]這樣的表示式也會匹配小寫字母。完整的 Unicode 匹配(例如Ü匹配ü)也能正常運作,除非使用了ASCII旗標來停用非 ASCII 的匹配。除非也使用了LOCALE旗標,否則目前的區域設定不會改變這個旗標的效果。對應到內嵌旗標
(?i)。請注意,當 Unicode 模式
[a-z]或[A-Z]與IGNORECASE旗標結合使用時,它們會匹配 52 個 ASCII 字母和另外 4 個非 ASCII 字母:'İ' (U+0130,帶點的大寫拉丁字母 I)、'ı' (U+0131,無點的小寫拉丁字母 i)、'ſ' (U+017F,拉丁小寫長 s)和 'K' (U+212A,開爾文符號)。如果使用了ASCII旗標,則只會匹配字母 'a' 到 'z' 和 'A' 到 'Z'。
- re.L¶
- re.LOCALE¶
使
\w、\W、\b、\B和不區分大小寫的匹配依賴於目前的區域設定。這個旗標只能用在位元組模式中。對應到內嵌旗標
(?L)。警告
不建議使用這個旗標;請考慮使用 Unicode 匹配。區域設定機制非常不可靠,因為它一次只處理一種「文化」,並且只適用於 8 位元的區域設定。Unicode 匹配在 Unicode(字串)模式中預設是啟用的,並且能夠處理不同的區域設定和語言。
在 3.7 版的變更:使用
LOCALE旗標的已編譯正規表示式物件不再依賴於編譯時的區域設定。只有匹配時的區域設定會影響匹配的結果。
- re.M¶
- re.MULTILINE¶
當指定時,模式字元
'^'會在字串的開頭以及每一行的開頭(緊接在每個換行符號之後)匹配;而模式字元'$'會在字串的結尾以及每一行的結尾(緊接在每個換行符號之前)匹配。預設情況下,'^'只會在字串的開頭匹配,而'$'只會在字串的結尾以及字串結尾(如果有的話)緊接在換行符號之前匹配。對應到內嵌旗標
(?m)。
- re.NOFLAG¶
表示沒有應用任何旗標,值為
0。這個旗標可以用作函式關鍵字引數的預設值,或是作為一個基底值,將會有條件地與其他旗標進行 OR 運算。作為預設值使用的範例:defmyfunc(text,flag=re.NOFLAG):returnre.match(text,flag)
在 3.11 版被加入.
- re.U¶
- re.UNICODE¶
在 Python 3 中,Unicode 字元在
str模式中預設會被匹配。因此這個旗標是多餘的,沒有任何效果,並且僅為了向後相容而保留。請參閱
ASCII以將匹配限制為 ASCII 字元。
- re.X¶
- re.VERBOSE¶
這個旗標透過讓你在視覺上分隔模式的邏輯區塊並添加註解,使你能夠撰寫看起來更好且更易讀的正規表示式。模式中的空白會被忽略,除非在字元類別中,或是前面有一個未跳脫的反斜線,或是在像是
*?、(?:或(?P<...>這樣的標記中。例如,(?:和*?是不允許的。當一行包含一個不在字元類別中且前面沒有未跳脫反斜線的#時,從最左邊的這個#到行尾的所有字元都會被忽略。這表示下面兩個匹配十進位數字的正規表示式物件在功能上是相等的:
a=re.compile(r"""\d + # 整數部分 \. # 小數點 \d * # 一些小數位""",re.X)b=re.compile(r"\d+\.\d*")
對應到內嵌旗標
(?x)。
函式¶
- re.compile(pattern,flags=0)¶
將正規表示式模式編譯成正規表示式物件,可以使用它的
match()、search()等方法來匹配,如下所述。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。序列為:
prog=re.compile(pattern)result=prog.match(string)
等價於:
result=re.match(pattern,string)
但是當表示式在單一程式中多次使用時,使用
re.compile()並保存產生的正規表示式物件以供重複使用會更有效率。備註
傳遞給
re.compile()之最新模式的編譯版本和模組層級匹配函式都會被快取,因此一次僅使用幾個正規表示式的程式不必去擔心編譯正規表示式。
- re.search(pattern,string,flags=0)¶
掃描string 以尋找正規表示式pattern 產生匹配的第一個位置,並回傳對應的
Match。如果字串中沒有與模式匹配的位置則回傳None;請注意,這與在字串中的某個點查找零長度匹配不同。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。
- re.match(pattern,string,flags=0)¶
如果string 開頭的零個或多個字元與正規表示式pattern 匹配,則回傳對應的
Match。如果字串與模式不匹配,則回傳None;請注意,這與零長度匹配不同。請注意,即使在
MULTILINE模式 (mode) 下,re.match()只會於字串的開頭匹配,而非每行的開頭。如果你想在string 中的任何位置找到匹配項,請使用
search()(另請參閱search() vs. match())。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。
- re.fullmatch(pattern,string,flags=0)¶
如果整個string 與正規表示式pattern 匹配,則回傳對應的
Match。如果字串與模式不匹配,則回傳None;請注意,這與零長度匹配不同。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。在 3.4 版被加入.
- re.split(pattern,string,maxsplit=0,flags=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.',maxsplit=1)['Words', 'words, words.']>>>re.split('[a-f]+','0a3B9',flags=re.IGNORECASE)['0', '3', '9']
如果分隔符號中有捕獲群組並且它在字串的開頭匹配,則結果將以空字串開頭。這同樣適用於字串的結尾:
>>>re.split(r'(\W+)','...words, words...')['', '...', 'words', ', ', 'words', '...', '']
如此一來,分隔符號元件始終可以在結果串列中的相同相對索引處找到。
Adjacent empty matches are not possible, but an empty match can occurimmediately after a non-empty match.
>>>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', '...', '', '', '']
可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。在 3.1 版的變更:新增可選旗標引數。
在 3.7 版的變更:新增了對可以匹配空字串之模式進行拆分的支援。
在 3.13 版之後被棄用:將maxsplit 和flags 作為位置引數傳遞的用法已被棄用。在未來的 Python 版本中,它們將會是僅限關鍵字參數。
- re.findall(pattern,string,flags=0)¶
以字串或元組串列的形式回傳string 中pattern 的所有非重疊匹配項。從左到右掃描string,並按找到的順序回傳符合項目。結果中會包含空匹配項。
結果取決於模式中捕獲群組的數量。如果沒有群組,則回傳與整個模式匹配的字串串列。如果恰好存在一個群組,則回傳與該群組匹配的字串串列。如果存在多個群組,則回傳與群組匹配的字串元組串列。非捕獲群組則不影響結果的形式。
>>>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')]
可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。在 3.7 版的變更:非空匹配現在可以剛好在前一個空匹配的後面開始。
- re.finditer(pattern,string,flags=0)¶
回傳一個iterator,在string 中的 REpattern 的所有非重疊匹配上 yield
Match物件。從左到右掃描string,並按找到的順序回傳匹配項目。結果中包含空匹配項。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。在 3.7 版的變更:非空匹配現在可以剛好在前一個空匹配的後面開始。
- re.sub(pattern,repl,string,count=0,flags=0)¶
回傳透過以替換repl 取代string 中最左邊不重疊出現的pattern 所獲得的字串。如果未找到該模式,則不改變string 並回傳。repl 可以是字串或函式;如果它是字串,則處理其中的任何反斜線跳脫。也就是說
\n會被轉換為單一換行符、\r會被轉換為回車符 (carriage return) 等等。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 的每個不重疊出現之處都會呼叫它。此函式接收單一
Match引數,並回傳替換字串。例如:>>>defdashrepl(matchobj):...ifmatchobj.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'
此模式可以是字串或
Pattern。可選引數count 是要替換的模式出現的最大次數;count 必須是非負整數。如果省略或為零,則所有出現的內容都將被替換。
Adjacent empty matches are not possible, but an empty match can occurimmediately after a non-empty match.As a result,
sub('x*','-','abxd')returns'-a-b--d-'instead of'-a-b-d-'.在字串型別repl 引數中,除了上述字元跳脫和反向參照之外,
\g<name>將使用名為name的群組所匹配到的子字串,如(?P<name>...)所定義的語法。\g<number>使用對應的群組編號;因此\g<2>等價於\2,但在諸如\g<2>0之類的替換中並非模糊不清 (isn't ambiguous)。\20將被直譯為對群組 20 的參照,而不是對後面跟著字面字元'0'的群組 2 的參照。反向參照\g<0>會取代以 RE 所匹配到的整個子字串。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。在 3.1 版的變更:新增可選旗標引數。
在 3.5 版的變更:不匹配的群組將被替換為空字串。
在 3.6 版的變更:在由
'\'和一個 ASCII 字母組成之pattern 中的未知跳脫符現在為錯誤。在 3.7 版的變更:由
'\'和一個 ASCII 字母組成之repl 中的未知跳脫符現在為錯誤。非空匹配後可以緊接著出現空匹配。在 3.12 版的變更:群組id 只能包含 ASCII 數字。在
bytes替換字串中,群組name 只能包含 ASCII 範圍內的位元組 (b'\x00'-b'\x7f')。在 3.13 版之後被棄用:將count 和flags 作為位置引數傳遞的用法已被棄用。在未來的 Python 版本中,它們將會是僅限關鍵字參數。
- re.subn(pattern,repl,string,count=0,flags=0)¶
執行與
sub()相同的操作,但回傳一個元組(new_string,number_of_subs_made)。可以透過指定flags 值來修改正規表示式的行為,值可以是任何flags 變數,使用位元 OR(bitwise OR、
|運算子)組合。
- re.escape(pattern)¶
對pattern 中的特殊字元進行跳脫。如果你想要匹配其中可能包含正規表示式元字元 (metacharacter) 的任何文本字串,這會非常有用。例如:
>>>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))))/|\-|\+|\*\*|\*
此函式不得用於
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 版的變更:Only characters that can have special meaning in a regular expressionare escaped. As a result,
'!','"','%',"'",',','/',':',';','<','=','>','@', and"`"are no longer escaped.
- re.purge()¶
清除正規表示式快取。
例外¶
- exceptionre.PatternError(msg,pattern=None,pos=None)¶
當傳遞給此處函式之一的字串不是有效的正規表示式(例如它可能包含不匹配的括號)或在編譯或匹配期間發生某些其他錯誤時,將引發例外。如果字串不包含模式匹配項,則絕不是錯誤。
PatternError實例具有以下附加屬性:- msg¶
未格式化的錯誤訊息。
- pattern¶
正規表示式模式。
- pos¶
pattern 中編譯失敗的索引(可能是
None)。
- lineno¶
對應pos 的列(可能是
None)。
- colno¶
對應pos 的欄(可能是
None)。
在 3.5 版的變更:新增額外屬性。
在 3.13 版的變更:
PatternError最初被命名為error;後者為了向後相容性而被保留為別名。
正規表示式物件¶
- classre.Pattern¶
由
re.compile()回傳的已編譯正規表示式物件。在 3.9 版的變更:
re.Pattern支援[]以表示 Unicode(字串)或位元組模式。請參閱泛型別名型別。
- Pattern.search(string[,pos[,endpos]])¶
掃描string 以尋找此正規表示式產生匹配的第一個位置,並回傳對應的
Match。如果字串中沒有與模式匹配的位置則回傳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")# 在索引 0 處匹配<re.Match object; span=(0, 1), match='d'>>>>pattern.search("dog",1)# 無匹配;搜尋不包含 "d"
- Pattern.match(string[,pos[,endpos]])¶
如果在string 的開頭處有零個或多個字元與此正規表示式匹配,則回傳對應的
Match。如果字串與模式不匹配,則回傳None;請注意,這與零長度匹配不同。可選的pos 和endpos 參數與
search()方法中的參數具有相同的意義。>>>pattern=re.compile("o")>>>pattern.match("dog")# 無匹配,因為 "o" 不在 "dog" 的開頭。>>>pattern.match("dog",1)# 匹配,因為 "o" 是 "dog" 的第二個字元。<re.Match object; span=(1, 2), match='o'>
如果你想在string 中的任何位置找到匹配,請改用
search()(另請參閱search() vs. match())。
- Pattern.fullmatch(string[,pos[,endpos]])¶
如果整個string 與此正規表示式匹配,則回傳對應的
Match。如果字串與模式不匹配,則回傳None;請注意,這與零長度匹配不同。可選的pos 和endpos 參數與
search()方法中的參數具有相同的意義。>>>pattern=re.compile("o[gh]")>>>pattern.fullmatch("dog")# 無匹配,因為 "o" 不在 "dog" 的開頭。>>>pattern.fullmatch("ogre")# 無匹配,因為整個字串不匹配。>>>pattern.fullmatch("doggie",1,3)# 在給定限制內匹配。<re.Match object; span=(1, 3), match='og'>
在 3.4 版被加入.
- Pattern.findall(string[,pos[,endpos]])¶
類似於
findall()函式,使用已編譯的模式,但也接受可選的pos 和endpos 參數,這些參數會像search()一樣限制搜尋區域。
- Pattern.finditer(string[,pos[,endpos]])¶
類似於
finditer()函式,使用已編譯的模式,但也接受可選的pos 和endpos 參數,這些參數會像search()一樣限制搜尋區域。
- Pattern.groups¶
模式中捕獲群組的數量。
- Pattern.groupindex¶
一個字典,將任何由
(?P<id>)定義的符號群組名稱對映到群組編號。如果模式中未使用符號群組,則字典為空。
- Pattern.pattern¶
從中編譯出模式物件的模式字串。
在 3.7 版的變更:新增對copy.copy() 和copy.deepcopy() 的支援。已編譯的正規表示式物件被視為不可分割的 (atomic)。
Match Objects¶
Match objects always have a boolean value ofTrue.Sincematch() andsearch() returnNonewhen there is no match, you can test whether there was a match with a simpleif statement:
match=re.search(pattern,string)ifmatch:process(match)
- classre.Match¶
Match object returned by successful
matches andsearches.
- Match.expand(template)¶
Return the string obtained by doing backslash substitution on the templatestringtemplate, as done by the
sub()method.Escapes such as\nare converted to the appropriate characters,and numeric backreferences (\1,\2) and named backreferences(\g<1>,\g<name>) are replaced by the contents of thecorresponding group. The backreference\g<0>will bereplaced by the entire match.在 3.5 版的變更:不匹配的群組將被替換為空字串。
- Match.group([group1,...])¶
Returns one or more subgroups of the match. If there is a single argument, theresult is a single string; if there are multiple arguments, the result is atuple with one item per argument. Without arguments,group1 defaults to zero(the whole match is returned). If agroupN argument is zero, the correspondingreturn value is the entire matching string; if it is in the inclusive range[1..99], it is the string matching the corresponding parenthesized group. If agroup number is negative or larger than the number of groups defined in thepattern, an
IndexErrorexception is raised. If a group is contained in apart of the pattern that did not match, the corresponding result isNone.If a group is contained in a part of the pattern that matched multiple times,the last match is returned.>>>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')
If the regular expression uses the
(?P<name>...)syntax, thegroupNarguments may also be strings identifying groups by their group name. If astring argument is not used as a group name in the pattern, anIndexErrorexception is raised.A moderately complicated example:
>>>m=re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)","Malcolm Reynolds")>>>m.group('first_name')'Malcolm'>>>m.group('last_name')'Reynolds'
Named groups can also be referred to by their index:
>>>m.group(1)'Malcolm'>>>m.group(2)'Reynolds'
If a group matches multiple times, only the last match is accessible:
>>>m=re.match(r"(..)+","a1b2c3")# Matches 3 times.>>>m.group(1)# Returns only the last match.'c3'
- Match.__getitem__(g)¶
This is identical to
m.group(g). This allows easier access toan individual group from a match:>>>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'
Named groups are supported as well:
>>>m=re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)","Isaac Newton")>>>m['first_name']'Isaac'>>>m['last_name']'Newton'
在 3.6 版被加入.
- Match.groups(default=None)¶
Return a tuple containing all the subgroups of the match, from 1 up to howevermany groups are in the pattern. Thedefault argument is used for groups thatdid not participate in the match; it defaults to
None.舉例來說:
>>>m=re.match(r"(\d+)\.(\d+)","24.1632")>>>m.groups()('24', '1632')
If we make the decimal place and everything after it optional, not all groupsmight participate in the match. These groups will default to
Noneunlessthedefault argument is given:>>>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)¶
Return a dictionary containing all thenamed subgroups of the match, keyed bythe subgroup name. Thedefault argument is used for groups that did notparticipate in the match; it defaults to
None. For example:>>>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])¶
Return the indices of the start and end of the substring matched bygroup;group defaults to zero (meaning the whole matched substring). Return
-1ifgroup exists but did not contribute to the match. For a match objectm, anda groupg that did contribute to the match, the substring matched by groupg(equivalent tom.group(g)) ism.string[m.start(g):m.end(g)]
Note that
m.start(group)will equalm.end(group)ifgroup matched anull string. For example, afterm=re.search('b(c?)','cba'),m.start(0)is 1,m.end(0)is 2,m.start(1)andm.end(1)are both2, andm.start(2)raises anIndexErrorexception.An example that will removeremove_this from email addresses:
>>>email="tony@tiremove_thisger.net">>>m=re.search("remove_this",email)>>>email[:m.start()]+email[m.end():]'tony@tiger.net'
- Match.span([group])¶
For a matchm, return the 2-tuple
(m.start(group),m.end(group)). Notethat ifgroup did not contribute to the match, this is(-1,-1).group defaults to zero, the entire match.
- Match.pos¶
The value ofpos which was passed to the
search()ormatch()method of aregex object. This isthe index into the string at which the RE engine started looking for a match.
- Match.endpos¶
The value ofendpos which was passed to the
search()ormatch()method of aregex object. This isthe index into the string beyond which the RE engine will not go.
- Match.lastindex¶
The integer index of the last matched capturing group, or
Noneif no groupwas matched at all. For example, the expressions(a)b,((a)(b)), and((ab))will havelastindex==1if applied to the string'ab', whilethe expression(a)(b)will havelastindex==2, if applied to the samestring.
- Match.lastgroup¶
The name of the last matched capturing group, or
Noneif the group didn'thave a name, or if no group was matched at all.
- Match.re¶
Theregular expression object whose
match()orsearch()method produced this match instance.
在 3.7 版的變更:Added support ofcopy.copy() andcopy.deepcopy(). Match objectsare considered atomic.
Regular Expression Examples¶
Checking for a Pair¶
In this example, we'll use the following helper function to display matchobjects a little more gracefully:
defdisplaymatch(match):ifmatchisNone:returnNonereturn'<Match:%r, groups=%r>'%(match.group(),match.groups())
Suppose you are writing a poker program where a player's hand is represented asa 5-character string with each character representing a card, "a" for ace, "k"for king, "q" for queen, "j" for jack, "t" for 10, and "2" through "9"representing the card with that value.
To see if a given string is a valid hand, one could do the following:
>>>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=()>"
That last hand,"727ak", contained a pair, or two of the same valued cards.To match this with a regular expression, one could use backreferences as such:
>>>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',)>"
To find out what card the pair consists of, one could use thegroup() method of the match object in the following manner:
>>>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>", line1, in<module>re.match(r".*(.).*\1","718ak").group(1)AttributeError:'NoneType' object has no attribute 'group'>>>pair.match("354aa").group(1)'a'
模擬 scanf()¶
Python does not currently have an equivalent toscanf(). Regularexpressions are generally more powerful, though also more verbose, thanscanf() format strings. The table below offers some more-or-lessequivalent mappings betweenscanf() format tokens and regularexpressions.
| Regular Expression |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To extract the filename and numbers from a string like
/usr/sbin/sendmail-0errors,4warnings
you would use ascanf() format like
%s-%derrors,%dwarnings
The equivalent regular expression would be
(\S+)-(\d+)errors,(\d+)warnings
search() vs. match()¶
Python offers different primitive operations based on regular expressions:
re.match()checks for a match only at the beginning of the stringre.search()checks for a match anywhere in the string(this is what Perl does by default)re.fullmatch()checks for entire string to be a match
舉例來說:
>>>re.match("c","abcdef")# No match>>>re.search("c","abcdef")# Match<re.Match object; span=(2, 3), match='c'>>>>re.fullmatch("p.*n","python")# Match<re.Match object; span=(0, 6), match='python'>>>>re.fullmatch("r.*n","python")# No match
Regular expressions beginning with'^' can be used withsearch() torestrict the match at the beginning of the string:
>>>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'>
Note however that inMULTILINE modematch() only matches at thebeginning of the string, whereas usingsearch() with a regular expressionbeginning with'^' will match at the beginning of each line.
>>>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'>
Making a Phonebook¶
split() splits a string into a list delimited by the passed pattern. Themethod is invaluable for converting textual data into data structures that can beeasily read and modified by Python as demonstrated in the following example thatcreates a phonebook.
First, here is the input. Normally it may come from a file, here we are usingtriple-quoted string syntax
>>>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"""
The entries are separated by one or more newlines. Now we convert the stringinto a list with each nonempty line having its own entry:
>>>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']
Finally, split each entry into a list with first name, last name, telephonenumber, and address. We use themaxsplit parameter ofsplit()because the address has spaces, our splitting pattern, in it:
>>>[re.split(":? ",entry,maxsplit=3)forentryinentries][['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']]
The:? pattern matches the colon after the last name, so that it does notoccur in the result list. With amaxsplit of4, we could separate thehouse number from the street name:
>>>[re.split(":? ",entry,maxsplit=4)forentryinentries][['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']]
Text Munging¶
sub() replaces every occurrence of a pattern with a string or theresult of a function. This example demonstrates usingsub() witha function to "munge" text, or randomize the order of all the charactersin each word of a sentence except for the first and last characters:
>>>defrepl(m):...inner_word=list(m.group(2))...random.shuffle(inner_word)...returnm.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.'
Finding all Adverbs¶
findall() matchesall occurrences of a pattern, not just the firstone assearch() does. For example, if a writer wanted tofind all of the adverbs in some text, they might usefindall() inthe following manner:
>>>text="He was carefully disguised but captured quickly by police.">>>re.findall(r"\w+ly\b",text)['carefully', 'quickly']
Finding all Adverbs and their Positions¶
If one wants more information about all matches of a pattern than the matchedtext,finditer() is useful as it providesMatch objectsinstead of strings. Continuing with the previous example, if a writer wantedto find all of the adverbsand their positions in some text, they would usefinditer() in the following manner:
>>>text="He was carefully disguised but captured quickly by police.">>>forminre.finditer(r"\w+ly\b",text):...print('%02d-%02d:%s'%(m.start(),m.end(),m.group(0)))07-16: carefully40-47: quickly
Raw String Notation¶
Raw string notation (r"text") keeps regular expressions sane. Without it,every backslash ('\') in a regular expression would have to be prefixed withanother one to escape it. For example, the two following lines of code arefunctionally identical:
>>>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 '>
When one wants to match a literal backslash, it must be escaped in the regularexpression. With raw string notation, this meansr"\\". Without raw stringnotation, one must use"\\\\", making the following lines of codefunctionally identical:
>>>re.match(r"\\",r"\\")<re.Match object; span=(0, 1), match='\\'>>>>re.match("\\\\",r"\\")<re.Match object; span=(0, 1), match='\\'>
Writing a Tokenizer¶
Atokenizer or scanneranalyzes a string to categorize groups of characters. This is a useful firststep in writing a compiler or interpreter.
The text categories are specified with regular expressions. The technique isto combine those into a single master regular expression and to loop oversuccessive matches:
fromtypingimportNamedTupleimportreclassToken(NamedTuple):type:strvalue:strline:intcolumn:intdeftokenize(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)'%pairforpairintoken_specification)line_num=1line_start=0formoinre.finditer(tok_regex,code):kind=mo.lastgroupvalue=mo.group()column=mo.start()-line_startifkind=='NUMBER':value=float(value)if'.'invalueelseint(value)elifkind=='ID'andvalueinkeywords:kind=valueelifkind=='NEWLINE':line_start=mo.end()line_num+=1continueelifkind=='SKIP':continueelifkind=='MISMATCH':raiseRuntimeError(f'{value!r} unexpected on line{line_num}')yieldToken(kind,value,line_num,column)statements=''' IF quantity THEN total := total + price * quantity; tax := price * 0.05; ENDIF;'''fortokenintokenize(statements):print(token)
The tokenizer produces the following output:
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)
Friedl, Jeffrey. Mastering Regular Expressions. 3rd ed., O'ReillyMedia, 2009. The third edition of the book no longer covers Python at all,but the first edition covered writing good regular expression patterns ingreat detail.