为什么这个正则表达式不贪心?

时间:2012-10-14 02:33:52

标签: regex perl

在这个正则表达式中

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

print $line;

为什么$ 2等于" is a regular "?我的思维过程是(。*)应该贪婪并匹配所有字符,直到行结束,因此$ 3将为空。

但是,这并没有发生。正则表达式匹配器以某种方式在最后一个单词边界之前停止,并在最后一个单词边界之后填充$ 3,并将其余字符串发送到$ 2。

任何解释? 谢谢。

4 个答案:

答案 0 :(得分:15)

使用此正则表达式时,

$3不能为空,因为相应的捕获组为(\w+),必须至少匹配一个单词字符,否则整个匹配将失败。

所以会发生(.*)匹配“is a regular expression”,\b匹配字符串的结尾,(\w+)无法匹配。然后正则表达式引擎回溯到(.*)匹配“is a regular "(请注意匹配包含空格),\b匹配e之前的字边界,(\w+)匹配“expression”。

如果您将(\w+)更改为(\w*),那么您将得到预期的结果,其中(.*)会消耗整个字符串。

答案 1 :(得分:6)

贪婪并不意味着它绝对匹配所有东西。它只是意味着它可以尽可能多地并且仍然具有正则表达式成功

这意味着,由于您在第3组中使用+,因此它不能为空且仍然成功,因为+表示 1或更多

如果您希望3为空,只需将(\w+)更改为(\w?)即可。现在,因为?表示0或1,它可以为空,因此贪婪的.*会占用所有内容。注意:这似乎仅适用于Perl,因为perl处理行。

答案 2 :(得分:1)

为了使正则表达式与整个字符串匹配,^(\w+)\b要求整个第一个单词为\1。同样,\b(\w+)$要求整个最后一个单词为\3。因此,无论多么贪婪(.*),它只能捕获'是常规',否则模式将不匹配。在匹配字符串的某个时刻,.*可能确实占用了整个'是一个正则表达式',但后来发现它必须回溯并让\w+得到它的匹配。

答案 3 :(得分:0)

你编写正则表达式的方式无论.*是贪婪还是非贪婪都无关紧要。 它仍然会匹配。

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

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']