使用Perl中的regex在字符串中获取多个匹配项

Acs*_*sor 5 regex perl multiple-matches

在阅读了这个类似的问题并多次尝试我的代码之后,我继续获得相同的不良输出.

让我们假设我正在搜索的字符串是"我昨天看到了wilma".正则表达式应该捕获每个单词后跟一个'a'及其可选的 5个后面的字符或空格.

我写的代码如下:

$_ = "I saw wilma yesterday";

if (@m = /(\w+)a(.{5,})?/g){
    print "found " . @m . " matches\n";

    foreach(@m){
        print "\t\"$_\"\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我继续获得以下输出:

found 2 matches
    "s"
    "w wilma yesterday"
Run Code Online (Sandbox Code Playgroud)

虽然我希望得到以下一个:

found 3 matches:
    "saw wil"
    "wilma yest"
    "yesterday"
Run Code Online (Sandbox Code Playgroud)

直到我发现里面的返回值@m$1$2,你可以注意到.

现在,由于/g标志已打开,我认为问题不在于正则表达式,我怎样才能获得所需的输出?

Cas*_*yte 3

您可以尝试这种允许重叠结果的模式:

(?=\b(\w+a.{1,5}))
Run Code Online (Sandbox Code Playgroud)

或者

(?=(?i)\b([a-z]+a.{0,5}))
Run Code Online (Sandbox Code Playgroud)

例子:

use strict;
my $str = "I saw wilma yesterday";
my @matches = ($str =~ /(?=\b([a-z]+a.{0,5}))/gi);
print join("\n", @matches),"\n";
Run Code Online (Sandbox Code Playgroud)

更多解释:

正则表达式的结果不能重叠,因为当一个字符被正则表达式引擎“吃掉”时,它就不能再被吃掉。避免这种约束的技巧是使用前瞻(即一种仅检查但不匹配的工具),它可以多次遍历字符串,并在其中放置一个捕获组。

对于此行为的另一个示例,您可以尝试不带单词边界 ( ) 的示例代码\b来查看结果。