使用conditional expression、code expression 和backtracking control verbs。
my $skips = 1;
$string =~ /^(.*)s(?(?{$skips-- > 0})(*FAIL))/;
以上将使用贪心匹配,但会导致最大匹配故意失败。如果您想要第三大,您可以将跳过的数量设置为 2。
如下所示:
#!/usr/bin/perl
use strict;
use warnings;
my $string = "111s11111s11111s";
$string =~ /^(.*)s/;
print "Greedy match - $1\n";
$string =~ /^(.*?)s/;
print "Ungreedy match - $1\n";
my $skips = 1;
$string =~ /^(.*)s(?(?{$skips-- > 0})(*FAIL))/;
print "2nd Greedy match - $1\n";
输出:
Greedy match - 111s11111s11111
Ungreedy match - 111
2nd Greedy match - 111s11111
在使用此类高级功能时,重要的是要全面了解正则表达式以预测结果。这种特殊情况有效,因为正则表达式在一端固定为^。这意味着我们知道每个后续匹配也比前一个短一个。但是,如果两端都可以移动,我们不一定能预测顺序。
如果是这样,那么你就找到它们,然后对它们进行排序:
use strict;
use warnings;
my $string = "111s11111s";
my @seqs;
$string =~ /^(.*)s(?{push @seqs, $1})(*FAIL)/;
my @sorted = sort {length $b <=> length $a} @seqs;
use Data::Dump;
dd @sorted;
输出:
("111s11111s11111", "111s11111", 111)
注意v5.18 之前的 Perl 版本
Perl v5.18 引入了一个更改,/(?{})/ and /(??{})/ have been heavily reworked,它使词法变量的范围能够在上面使用的代码表达式中正常工作。在此之前,上述代码会导致如下错误,如this subroutine version run under v5.16.2所示:
Variable "$skips" will not stay shared at (re_eval 1) line 1.
Variable "@seqs" will not stay shared at (re_eval 2) line 1.
RE 代码表达式的旧实现的修复方法是使用our 声明变量,并且为了进一步的良好编码实践,在初始化时使用localize 它们。这在modified subroutine version run under v5.16.2 中得到了证明,或者如下所示:
local our @seqs;
$string =~ /^(.*)s(?{push @seqs, $1})(*FAIL)/;