2012-10-14 34 views
9

在這個表達式爲什麼這個正則表達式不貪婪?

$line = 'this is a regular expression'; 
$line =~ s/^(\w+)\b(.*)\b(\w+)$/$3 $2 $1/; 

print $line; 

爲什麼是$ 2等於" is a regular "?我的思考過程是(。*)應該是貪婪的並且匹配所有字符,直到行尾,因此$ 3將是空的。

雖然這並未發生。正則表達式匹配器在最後一個單詞邊界之前以某種方式停止,並在最後一個單詞邊界之後填充$ 3,並將字符串的其餘部分發送到$ 2。

任何解釋? 謝謝。

回答

15

$3使用此正則表達式時不能爲空,因爲相應的捕獲組是(\w+),它必須匹配至少一個單詞字符,否則整個匹配將失敗。

所以會發生什麼是(.*)匹配「is a regular expression」,\b字符串的結尾匹配,並(\w+)不匹配。正則表達式引擎然後回溯到(.*)匹配「is a regular "(注意匹配包括空格),\b匹配e前的字邊界,並(\w+)匹配」 expression」。

如果更改(\w+)(\w*)那麼你將結束您預期的結果,其中(.*)消耗整個字符串。

+0

'$'是一個零寬度斷言;我認爲沒有任何消費(如果可能的話)字符串的結尾將是一個問題。參見:http://codepad.org/CwTlhn3z – NullUserException

+0

@NullUserException我也這麼認爲,但[^(\ w +)\ b(。*)\ b(\ w *)$](http://rubular.com/r/XczcfFd2Va)仍將'expression'與最後一組匹配。如我所料,使字邊界可選將導致空匹配。我不太確定實際上發生了什麼...... – verdesmarald

+0

看起來,Ruby的正則表達式引擎與Perl的不同。 – NullUserException

6

貪婪並不意味着它會以絕對一切相匹配。這只是意味着它可以採取儘可能,仍然有正則表達式成功

這意味着由於您在組3中使用+,因此它不能爲空並且仍然成功,因爲+表示1或更多

如果您希望3爲空,只需將(\w+)更改爲(\w?)即可。現在因爲?意味着0或1它可以是空的,因此貪婪.*採取一切。注意:由於perl處理線的方式,這似乎只適用於Perl。

+0

http://rubular.com/r/1XFcnXANWJ,儘管在Perl中它的工作原理與你所描述的一樣。在Perl中,字符串的結尾是否是單詞邊界? – NullUserException

+0

'(\ w?)'表示0或1,'(\ w *)'表示0或更多。 –

+0

@BradGilbert這是一個怎樣的問題? – NullUserException

1

爲了讓正則表達式匹配整個字符串,^(\w+)\b要求整個第一個單詞是\1。同樣,\b(\w+)$要求整個最後一個詞是\3。因此,無論多麼貪婪,它只能捕獲'是一個常規',否則模式將不匹配。在匹配字符串的某個時刻,.*可能確實佔用了整個「是一個正則表達式」,但後來發現它必須回溯並讓\w+也得到它的匹配。

0

您編寫正則表達式的方式與.*是貪婪還是非貪婪無關。 它仍然會匹配。

原因是您在.*\w+之間使用了\b

use strict; 
use warnings; 

my $string = 'this is a regular expression'; 

sub test{ 
    my($match,$desc) = @_; 
    print '# ', $desc, "\n" if $desc; 
    print "test(qr'$match');\n"; 
    if(my @elem = $string =~ $match){ 
    print ' 'x4,'[\'', join("']['",@elem), "']\n\n" 
    }else{ 
    print ' 'x4,"FAIL\n\n"; 
    } 
} 

test(qr'^ (\w+) \b (.*) \b (\w+) $'x, 'original'); 
test(qr'^ (\w+) \b (.*+) \b (\w+) $'x, 'extra-greedy'); 
test(qr'^ (\w+) \b (.*?) \b (\w+) $'x, 'non-greedy'); 
test(qr'^ (\w+) \b (.*) \b (\w*) $'x, '\w* instead of \w+'); 
test(qr'^ (\w+) \b (.*)  (\w+) $'x, 'no \b'); 
test(qr'^ (\w+) \b (.*?) (\w+) $'x, 'no \b, non-greedy .*?'); 
# original 
test(qr'(?^x:^ (\w+) \b (.*) \b (\w+) $)'); 
    ['this'][' is a regular ']['expression'] 

# extra-greedy 
test(qr'(?^x:^ (\w+) \b (.*+) \b (\w+) $)'); 
    FAIL 

# non-greedy 
test(qr'(?^x:^ (\w+) \b (.*?) \b (\w+) $)'); 
    ['this'][' is a regular ']['expression'] 

# \w* instead of \w+ 
test(qr'(?^x:^ (\w+) \b (.*) \b (\w*) $)'); 
    ['this'][' is a regular expression'][''] 

# no \b 
test(qr'(?^x:^ (\w+) \b (.*)  (\w+) $)'); 
    ['this'][' is a regular expressio']['n'] 

# no \b, non-greedy .*? 
test(qr'(?^x:^ (\w+) \b (.*?) (\w+) $)'); 
    ['this'][' is a regular ']['expression'] 
+0

我不知道的答案這個問題... –

+0

它顯示了對原始正則表達式的各種輕微修改。 –