2016-12-06 194 views
3

我發現,錨固在面前的時候,不要到最後非貪婪正則表達式匹配只能成爲非貪婪:正則表達式

$ echo abcabcabc | perl -ne 'print $1 if /^(a.*c)/' 
abcabcabc 
# OK, greedy match 

$ echo abcabcabc | perl -ne 'print $1 if /^(a.*?c)/' 
abc 
# YES! non-greedy match 

現在看這個錨,當到底:

$ echo abcabcabc | perl -ne 'print $1 if /(a.*c)$/' 
abcabcabc 
# OK, greedy match 

$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/' 
abcabcabc 
# what, non-greedy become greedy? 

這是爲什麼?它如何不像以前那樣打印abc

(問題發現在我的Go代碼中,但爲了簡單起見,在Perl中進行了說明)。

+0

'/(a.c *?)$ /'匹配'abcabcabc'中最後一個'abc'。既然你是錨定到最後,c應該是非貪婪的。 –

+0

@AdityaJ。,Nah,你已經改變了「算法」。對於你的「解決方案」,即使沒有'*?',即'/(a.c)$ /',它仍然可以工作。但是,謝謝你嘗試。 – xpt

+0

使用'。*?',正則表達式引擎開始匹配量詞允許的最小字符數 - **爲零**。引擎然後前進並嘗試下一個標記。這失敗了,所以引擎回溯並擴展其匹配。這個過程會重複 - 正則表達式引擎前進,失敗,回溯,再次擴展匹配,前進,失敗,...這是否定的情況'/ a [^ a] * c $ /' – hwnd

回答

7
$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/' 
abcabcabc 
# what, non-greedy become greedy? 

非貪婪意味着它會在當前位置,使得整個圖案匹配匹配的字符可能最少。

0位置匹配a後,bcabcab是至少.*?可以在1位置匹配,同時仍然滿足圖案的其餘部分。

"abcabcabc" = /a.*?c$/詳細:

  1. 在pos 0,a比賽1個炭(a)。
    1. 在pos 1,.*?匹配0個字符(空字符串)。
      1. 在pos 1,c不匹配。原路返回!
    2. 在pos 1,.*?找到1個字符(b)。
      1. 在pos 2,c符合1個字符(c)。
        1. 在pos 3,$不匹配。原路返回!
    3. 在pos 1,.*?比賽2個字符(bc)。
      1. 在pos 1,c不匹配。原路返回!
    4. ...
    5. 在pos 1,.*?匹配7個字符(bcabcab)。
      1. 在pos 8,c找到1個字符(c)。
        1. 在pos 9,$匹配0個字符(空字符串)。比賽成功!

詳細(供對比)"abcabcabc" = /a.*c$/

  1. 在pos 0,a比賽1個炭(a)。
    1. 在pos 1,.*匹配8個字符(abcabcabc)。
      1. 在pos 9,c不匹配。原路返回!
    2. 在pos 1,.*匹配7個字符(abcabcab)。
      1. 在pos 8,c找到1個字符(c)。
        1. 在pos 9,$匹配0個字符(空字符串)。比賽成功!

提示:避免模式與非貪婪改性劑的兩個實例。除非你將它們用作優化,否則很有可能他們可以匹配你不希望它們匹配的東西。這與此處相關,因爲模式隱含地以\G(?s:.*?)\K(除非被領先的^\A\G取消)。

你想要的是下列之一:

/a[^a]*c$/ 
/a[^c]*c$/ 
/a[^ac]*c$/ 

您還可以使用下列之一:

/a(?:(?!a).)c$/s 
/a(?:(?!c).)c$/s 
/a(?:(?!a|c).)c$/s 

這將是低效和不可讀在這種情況下使用這些後三位,但他們將使用長於一個字符的邊界。