$regex = "[M]?[VI]?[A]?[R]?[G]?[D]?[LM]?[G]?[IVMAL]?[E]?";
$text = "VMVARGDLGVE";
if (@matched = $text =~ /$regex/g) {
$no_of_match = scalar @matched;
print "No of match: ", $no_of_match, "\n";
foreach my $i (@matched) {
print $i, "\n";
}
}
该程序生成输出如下: 不匹配:3 VMV ARGDLGVE
我期待这个程序输出如下内容: V VM VMV MV MVA MVAR MVARG MVARGD MVARGDL MVARGDLG MVARGDLGV MVARGDLGVE ....
我试图将所有可能的匹配作为输出。如何获得所有可能的匹配?
答案 0 :(得分:1)
正则表达式匹配并不像那样工作。如果您在找到匹配项后再次搜索,则会从该匹配项的结尾再次开始搜索 。所以它没有找到重叠的匹配。
我假设你在Perl 5工作。我相信在Perl 6中有一些方法可以做到这一点。这真的是一种不同的语言。我不知道任何其他语言可以找到你想要的重叠正则表达式匹配。
它找到的第一个匹配项是开头的子字符串VMV
。然后它从它停止的位置开始搜索,并找到匹配ARGDLGVE
。然后它再次从它停止的地方开始尝试,这个阶段在字符串的末尾。所以它在末尾找到空子串作为匹配。 (请注意,你的正则表达式与空字符串匹配。)禁止正则表达式再次找到相同的空字符串,因为这会导致无限循环,因此它会停止搜索。
这段代码的重点是什么?因为我真的无法看到这样做的好方法,我希望还有其他方法来实现你的目标。您可以浏览$text
的所有可能的子字符串,并使用/^$regex$/
分别检查每个子字符串。根据我的计算,您将找到70个匹配项(包括重复项和空字符串)。也许你想要一个更严格的正则表达式?
答案 1 :(得分:1)
我已经重构了您的代码,以便更容易地查看正在进行的操作。
my $regex = qr/
M? # 1: Match M, greedy, 0 or 1 times.
[VI]? # 2: Match V or I, greedy, 0 or 1 times.
A? # 3: Match A, greedy, 0 or 1 times.
R? # 4: Match R, greedy, 0 or 1 times.
G? # 5: Match G, greedy, 0 or 1 times.
D? # 6: Match D, greedy, 0 or 1 times.
[LM]? # 7: Match L or M, greedy, 0 or 1 times.
G? # 8: Match G, greedy, 0 or 1 times.
[IVMAL]? # 9: Match I, B, M, A or L, greedy, 0 or 1 times.
E? # 10: Match E, greedy, 0 or 1 times.
/x;
my $text = "VMVARGDLGVE";
if ( my @matched = $text =~ /$regex/gx ) {
print "No of matches: ", scalar(@matched), "\n";
print "<<$_>>\n" foreach @matched;
}
您的正则表达式在尽可能多的方式匹配,而不会违反其NFA正则表达式引擎的规则。
其中一条规则是&#34;最左边&#34 ;;最靠近左边的子串 在目标中,将选择总匹配成功。
另一个规则是贪婪的量词将与之匹配 可能的,只会放弃他们拥有的子匹配 必须让完整的比赛成功。放弃一部分 他们的比赛涉及回溯。除非a。避免回溯 量词已经占用太多,必须放弃它以允许 完全匹配才能成功。
另一个规则是迭代匹配在该点恢复 上一场比赛没有结束。
穿过目标字符串,&#34; V&#34;匹配子模式[VI]?
(以下称为子模式#2)。贪婪的量词持有&#39; V&#39;并且只有在以后被强制使用时才会释放它,以获得更大的利益。
&#34; M&#34;从目标字符串匹配子模式#7。并且&#34; V&#34;匹配子模式#9。完成第一次迭代,匹配&#34; VMV&#34;。
现在,您的目标字符串的其余部分看起来像&#34; ARGDLGVE&#34;。 pos
标记位于3(目标字符串中的第4个字符),因此第二次迭代的匹配从那里开始。 &#39; A&#39;子模式#3,&#39; R&#39;比赛#4,&#39; G&#39;比赛#5,&#39; D&#39;比赛在#6,&#39; L&#39;比赛#7,&#39; G&#39;比赛#8,&#39; V&#39;比赛#9,&#39; E&#39;比赛在#10。第二次迭代完成,匹配了#ARGDLGVE&#39;来自目标字符串。
在第三次迭代中,pos
标记位于11,它位于目标字符串中的最后一个字符之后。因此,将空字符串与正则表达式进行比较。因为正则表达式中的每个量词都是&#34; 0或1&#34;,正则表达式可以匹配空字符串。所以第三次迭代完成,匹配&#34;&#34; (空字符串)。
你有三场比赛:&#34; VMV&#34;,&#34; ARGDLGVE&#34;和&#34;&#34;。
您可能希望做的一件事是控制pos
标记。将正则表达式放在while循环中,在循环终止之前,从字符串的开头向前推进pos
个位置。但这只能解决您在上述第三条规则中遇到的问题。你仍然会遇到量词人做非常具体事情的问题,并且只是因为你觉得它很方便而不违反他们自己的规则。
关键是正则表达式引擎不是置换引擎。它的工作是确定给定的目标字符串是否与给定的模式匹配,遵循一组明确定义的(虽然有时令人困惑)规则。
我不确定您尝试解决的问题是什么。如果您只是尝试扩展一组范围,那么使用CPAN模块String::Range::Expand可能会获得更好的成功。可能还有其他CPAN模块可以为您进行范围扩展,但这可能是一个很好的起点。
答案 2 :(得分:1)
这与Count overlapping regex matches in Perl OR Ruby几乎相同。
此代码与perldoc perlre几乎没有变化,在标题为“Special Backtracking Control Verbs”的部分中:
use strict;
use warnings;
my $regex = qr/M?[VI]?A?R?G?D?[LM]?G?[IVMAL]?E?/;
my $text = 'VMVARGDLGVE';
my $count = 0;
$text =~ /$regex(?{print "$&\n"; $count++})(*FAIL)/g;
print "Got $count matches\n";
脚本会计算空字符串匹配,以计算97次匹配。