[英]Match the nth longest possible string in Perl
Perl正则表达式的模式匹配量词是“贪婪的”(它们匹配最长的可能字符串)。 为了迫使比赛“不合适”,一个? 可以附加到模式量词(*,+)。
这是一个例子:
#!/usr/bin/perl
$string="111s11111s";
#-- greedy match
$string =~ /^(.*)s/;
print "$1\n"; # prints 111s11111
#-- ungreedy match
$string =~ /^(.*?)s/;
print "$1\n"; # prints 111
但是如何在Perl中找到第二,第三和......可能的字符串匹配? 举一个你的简单例子 - 如果需要更好的一个。
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
引入了一个更改, /(?{})/
和/(??{})
/已经过大量重写 ,使得词法变量的范围能够在上面使用的代码表达式中正常工作。 在此之前,上面的代码会导致以下错误,如在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
。 这在v5.16.2下运行的这个修改过的子程序版本中得到了证明 ,或者如下所示:
local our @seqs;
$string =~ /^(.*)s(?{push @seqs, $1})(*FAIL)/;
首先获得所有可能的匹配。
my $string = "111s1111s11111s";
local our @matches;
$string =~ /^(.*)s(?{ push @matches, $1 })(?!)/;
这找到了
111s1111s11111
111s1111
111
然后,这只是找出哪一个是第二个longuest并过滤掉其他的问题。
use List::MoreUtils qw( uniq );
my $target_length = ( sort { $b <=> $a } uniq map length, @matches )[1];
@matches = uniq grep { length($_) == $target_length } @matches
if $target_length;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.