1. 程式人生 > 程式設計 >正則表示式量詞與貪婪的使用詳解

正則表示式量詞與貪婪的使用詳解

目錄
  • 0.寫在前面
  • 1.量詞
  • 2.貪婪模式前傳
    • 2.1 使用 a+ 進行匹配
    • 2.2 使用 a* 進行匹配
  • 3.貪婪模式
    • 4.非貪婪模式
      • 5.獨佔模式
        • 5.1 貪婪匹配過程
        • 5.2 非貪婪匹配過程
        • 5.3 獨佔匹配過程
      • 6.寫在最後

        0.寫在前面

        在上一篇文章中,我們學習了正則的一些基礎元字元,相信大家都已經忘卻的差不多了,可以點選上面的連結再溫習下。

        今天我們一起來學習下正則中量詞的三種匹配模式,貪婪模式、非貪婪模式、獨佔模式,這些模式會改變正則中量詞的匹配行為,是每次貪婪的匹配到更多呢,還是不貪婪見好就收呢,如果不瞭解這些,我們寫出的正則很可能是錯誤的,甚至會引發嚴重的線上效能問題。

        1.量詞

        本篇文章所講的內容和量詞關係比較密切,先回顧下:

        量詞

        我們還可以用 {m,n} 的方式來表示 * + ? 這3種元字元:

        元字元 同義表示方法 示例
        * {0,} ab*
        可以匹配
        a 或者 abb
        + {1,} ab+
        可以匹配
        ab 或者 abb
        但不能匹配 a
        ? {0,1} ab?
        可以匹配 a 或者 ab
        但不能匹配 abb

        2.貪婪模式前傳

        在正則中,表示次數的量詞預設是貪婪的,在貪婪模式下,會盡可能最大長度的去匹配目標字串,我們用正則 a+a* 來匹配字串 aaabb 測試一下。

        2.1 使用 a+ 進行匹配

        可以看到只匹配到了1個結果 aaa

        a+匹配

        對應的 程式碼如下:

        import re
        
        print(re.findall(r'a+','aaabb'))
        
        輸出:['aaa']
        

        2.2 使用 a* 進行匹配

        可以看到匹配到了4個結果,其中還有3個是空字串

        a*匹配.jpg

        對應的 Python 程式碼如下:

        import re
        
        print(re.findall(r'a*','aaabb'))
        
        輸出:['aaa','','']
        

        為什麼會匹配到空字串呢?因為星號(*)代表匹配0到多次,匹配0次就是空字串,那前面還有個 aaa 呢,為什麼 aaa 之間的空字串沒有被匹配到?

        這就引入到了我們今天要講的,貪婪模式www.cppcns.com與非貪婪模式,從字面上很好理解,貪婪模式就是儘可能多的匹配,非貪婪模式就是儘可能少的匹配。

        3.貪婪模式

        一起來分析下上面正則 a* 的匹配過程:

        字串 a a a b b 空字串
        下標 0 1 2 3 4 5

        匹配 開始 結束 說明 匹配內容
        第一次 0 3 到第一個字母b發現不匹配,輸出aaa aaa
        第二次 3 3 匹配剩下的bb,發現匹配不上,輸出空字串 空字串
        第三次 4 4 匹配剩下的b,發現匹配不上,輸出空字串 空字串
        第四次 5 5 匹配剩下的空字串,輸出空字串 空字串

        a* 在匹配字串 aaabb 時,會盡可能多的把前面的 a 都匹配上,直到第一個字母 b 不滿足要求為止,匹配上3個 a,後面每次匹配的都是空字串。

        看到這裡,相信你已經對貪婪模式有了更深的印象,貪婪模式的特點就是儘可能進行最大長度匹配,就是有多少要多少,下面我們在一起來看下與它完全相反的匹配模式。

        4.非貪婪模式

        上面講完了貪婪模式,貪婪模式是儘可能最大長度匹配,非貪婪模式就是儘可能最小長度匹配,在量詞的後面加一個問號(?),就成了非貪婪模式,比如 a*?

        非貪婪匹配

        對應的 Python 程式碼如下:

        import re
        
        // 貪婪匹配
        print(re.findall(r'a*','']
        
        // 非貪婪匹配
        print(re.findall(r'a*?','aaabb'))
        
        輸出:['','a','']
        

        學完了貪婪模式與非貪婪模式,你可能會問,我什麼情況下會用到呢,下面舉個栗子感受下:

        貪婪匹配例子

        非貪婪匹配例子

        需求是查詢一段字串中,所有雙引號括起來的內容,上面使用貪婪匹配與非貪婪匹配的對比,差別很明顯對吧。

        5.獨佔模式

        不管是貪婪模式,還是非貪婪模式,匹配過程中都需要發生回溯才能完成想要的功能,但www.cppcns.com是在有一些場景,我們不需要回溯,匹配不上直接返回失敗就可以了,因此正則匹配中還有另外一種模式,獨佔模式,它和貪婪模式很像,但匹配過程中不會發生回溯,在一些使用場景中效能會更好。

        先來講講什麼是回溯,再舉個栗子,有一個正則表示式和目標字串,我們分別看下在三種匹配模式下都發生了什麼:

        5.1 貪婪匹配過程

        正則表示式:awww.cppcns.comb{1,3}c

        目標字串:abbc

        在匹配時,b{1,3} 會盡可能長的去匹配目標字串,匹配完 abb 之後,因為要儘可能長的匹配(3個 b),目標字串中的c就會匹配不上,這個時候會發生向前回溯,吐出當前字元 c,用正則中的 c 去匹配,匹配成功。

        貪婪匹配過程

        import regex
        
        print(regex.findall(r'ab{1,3}c','abbc'))
        
        輸出:['abbc']
        

        5.2 非貪婪匹配過程

        正則表示式:ab{1,3}?c

        目標字串:abbc

        在匹配時,b{1,3} 會盡可能短的去匹配目標字串,匹配完 ab 之後,會直接用正則 c 去匹配目標字串剩下的 b,匹配不上,發生向前回溯,重新用正則 b{1,3} 匹配 目標字串剩下的 b,然後正則 c 匹配 目標字串剩下的 c,匹配成功。

        非貪婪匹配過程

        import regex
        
        print(regex.findall(r'ab{1,3}?c','abbc'))
        
        輸出:['abbc']
        

        5.3 獨佔匹配過程

        在量詞後面加上 + 就是獨佔模式。

        正則表示式:ab{1,2}+bc

        目標字串:abbc

        在匹配時,b{1,2} 會盡可能長的去匹配目標字串,匹配完 abb 之後,會用正則 b 匹配目標字串剩下的 c,匹配不上,不回溯,匹配失敗。

        獨佔匹配過程

        import regex
        
        print(regex.findall(r'ab{1,2}+bc','abbc'))http://www.cppcns.com
        
        輸出:[]
        

        6.寫在最後

        最後在總結下上面講到的內容:

        思維導圖

        到這裡,正則表示式的量詞與貪婪就講完了,如果有問題可以給我留言評論,謝謝。

        正則表示式線上校驗工具:https://regex101.com/

        到此這篇關於正則表示式量詞與貪婪的使用詳解的文章就介紹到這了,更多相關正則表示式 量詞與貪婪內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!