2013-11-23 38 views
1

當捕獲組後面是一個問號,反向引用顯示爲不可Perl - 反向引用在捕獲組後跟隨時不可用?

my $test = "this is a very long day indeed"; 

if ($test =~ m/^this.+(very).+(indeed)?/) { 
    print "It matched the regex.\n"; 
    print "$1 :: $2\n"; 
} 

這將打印

It matched the first test. 
very :: 

這是正常的行爲呢?我無法在任何文檔中找到它。我試圖匹配第二個捕獲組可能存在或不存在的日誌文件中的行。

+0

可能重複:http://stackoverflow.com/questions/12683713/optional-capture-group-not-capturing – Enissay

回答

4

這不是反向引用問題。來自上一組的字符與.+匹配,但不是由您的可選捕獲組匹配,因此最後一組匹配空字符串。

問題是您使用的貪婪量詞匹配所有可能的字符。由於你的最後一組是可選的,因此.+全部匹配直到行尾,正則表達式引擎不需要回溯到匹配你的字符串(並且不需要找到「確實」)。

一個簡單的方法來解決這個問題是使用一個懶惰的量詞,而不是和結束標記,迫使去行的末尾(因爲懶惰量詞儘快停止):

m/^this.+(very).+?(indeed)?$/ 

注意:如果「真的」並不總是字符串的最後一個字符,你必須之前$

+0

不工作:http://regex101.com/r/xF1vF5 – Enissay

+0

@Enissay:它現在已被糾正。 –

+0

[確實](http://regex101.com/r/bP7aI1):) – Enissay

1

添加.*這是關於greedyness,這是你的問題(即得到了由卡西米爾回答)附加的註釋。

默認情況下,意識到regex引擎將消耗所有它可以直到它找到滿足當前評估子表達式右側的子表達式。

任何時候你認爲用DOT metachar使用.+貪婪量詞都應該引出一個紅旗來思考兩次。如果可能的話,它會衝擊你想要的東西。

由於這個原因,嘗試用一些更具體的東西來代替它,這些東西沒有機會超過您的預期目標。

修改您的示例正則表達式可以稍微顯示如何發生這種情況。

my $test = "this is a very long day indeed, very long."; 

if ($test =~ m/ 

    ^
     (this)    # (1) 
     (.+)     # (2) 
     (very)    # (3) 
     (.+)     # (4) 
     (indeed)?   # (5) 

/x) { 
    print "All = '$&'\n"; 
    print "grp1 = '$1'\n"; 
    print "grp1 = '$2'\n"; 
    print "grp1 = '$3'\n"; 
    print "grp1 = '$4'\n"; 
} 

# Output >> 
# 
# All = 'this is a very long day indeed, very long.' 
# grp1 = 'this' 
# grp1 = ' is a very long day indeed, ' 
# grp1 = 'very' 
# grp1 = ' long.' 
#