默認情況下,正則表達式進行貪婪匹配。所謂“貪婪”,是指當匹配到多種長度的字符串時,選擇最長的;而非貪婪,就是在匹配多種長度的字符串時,選擇最短的。
默認情況下,正則表達在匹配字符時,會把字符消耗掉;可以使用環視結構來匹配位置,使得正則不消耗字符,即正則在匹配文本時,不消耗字符,只匹配位置。
一,貪婪特性
貪婪是正則表達式的默認屬性,如下的幾個例子都說明了正則表達式“貪婪”的特性:
>>> re.findall('hi*', 'hiiiii') ['hiiiii'] >>> re.findall('hi{2,}', 'hiiiii') ['hiiiii'] >>> re.findall('hi{1,3}', 'hiiiii') ['hiii']
二,非貪婪特性
當我們期望正則表達式“非貪婪”地進行匹配時,需要通過語法明確說明:
{2,5}? 捕獲2-5次,但是選擇次數最少的匹配
在這里,問號?可能會有些讓人犯暈,因為之前他已經有了自己的含義:前面的匹配出現0次或1次。其實,只要記住,當問號出現在表現不定次數的正則表達式之后時,就表示非貪婪匹配。
正則表達式的非貪婪特性使用?來啟動,非貪婪特性共有四種情況:
- *?
- +?
- ??
- {m,n}?
還是上面的那幾個例子,用非貪婪匹配,則結果如下:
>>> re.findall('hi*?', 'hiiiii') ['h'] >>> re.findall('hi{2,}?', 'hiiiii') ['hii'] >>> re.findall('hi{1,3}?', 'hiiiii') ['hi']
三,捕獲和非貪婪
在正則表達式匹配的過程中,其實存在“消耗字符”的過程,也就是說,一旦一個字符在匹配過程中被檢索(消耗)過,后面的匹配就不會再檢索這一字符了。
(?=exp) 捕獲,但不消耗字符,且匹配exp,返回位置
(?!exp) 捕獲,但不消耗字符,且不匹配exp,返回位置
知道這個特性有什么用呢?還是用例子說明,比如,我們想找出字符串中出現過1次以上的單詞:
>>> sentence = "Oh what a day, what a lovely day!" >>> re.findall(r'\b(\w+)\b.*\b\1\b', sentence) ['what']
這樣的正則表達式顯然無法完成任務,為什么呢?原因就是,在第一個(\w+)匹配到what,並且其后的\1也匹配到第二個what的時候,“Oh what a day, what”這一段子串都已經被正則表達式消耗了,所以之后的匹配,將直接從第二個what之后開始。自然地,這里只能找出一個出現了兩次的單詞。
那么解決方案,就和上面提到的(?=exp)語法相關了。這樣的語法可以在分組匹配的同時,不消耗字符串!所以,正確的書寫方式應該是:
>>> re.findall(r'\b(\w+)\b(?=.*\b\1\b)', sentence) ['what', 'a', 'day']
如果我們需要匹配一個至少包含兩個不同字母的單詞,則可以使用(?!exp)的語法:
>>> re.search(r'([a-z]).*(?!\1)[a-z]', 'aa', re.IGNORECASE) >>> re.search(r'([a-z]).*(?!\1)[a-z]', 'ab', re.IGNORECASE) <_sre.SRE_Match object; span=(0, 2), match='ab'>
參考文檔: