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。

有什么解释吗?谢谢。

4

4 回答 4

15

$3使用此正则表达式时不能为空,因为对应的捕获组是(\w+),它必须至少匹配一个单词字符,否则整个匹配将失败。

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

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

于 2012-10-14T02:36:34.537 回答
6

贪婪并不意味着它可以完全匹配所有东西。这只是意味着它可以尽可能多地使用并且仍然让正则表达式成功

这意味着,由于您使用+in 组 3 它不能为空,并且仍然成功作为+1或更多

如果您希望 3 为空,只需更改(\w+)(\w?). 现在,由于?表示 0 或 1,它可以是空的,因此贪婪者.*会拿走一切。注意:这似乎只在 Perl 中有效,因为 perl 是如何处理行的。

于 2012-10-14T02:38:05.360 回答
1

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

于 2012-10-14T03:20:49.000 回答
0

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

原因是您使用\b了 between.*\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']
于 2012-10-14T04:38:08.657 回答