如何根据 perl 中的匹配元素查找间隔?
How to finding intervals based on matching elements in perl.?
@t = qw(a b c d e + g h + j k m n l + h +);
@q = qw(a b c d e f g h i j k l m l j h h);
@s = qw(a b c d e f g h k j k l m l j h h);
foreach (0..$#q){
if($t[$_] eq ($q[$_] && $s[$_])){
print "$t[$_]";
}
print "$t[$_]-$t[$_]\n";
elsif($t[$_] eq '+' && $q[$_] eq $s[$_]){
print"$t[$_]";
}
else{
print "\n";
}
}
预期输出:
abcde+gh [1-8]
jk [10-11]
l+h+ [14-17]
此处@t
基于同时匹配@q
和@s
,打印区间也基于@t
。
我无法获得不匹配的间隔。请给我一个好的解决方案
您的代码存在您在第 4 次编辑时引入的语法错误。您不能将任何代码放在 if
的块及其 elseif
之外。如果我没理解错的话,您想知道数组 @q
、@s
和 @t
何时排列,其中 @t
允许使用 '+'
作为通配符.
这是一种解决方案。它使用 $start
变量来检查我们是否在区间内并存储开头。如果我们处于区间或数组的末尾。我们打印间隔长度。可能有更好的方法来格式化它。最好的办法是引入更复杂的临时对象。如果您对区间开始和结束的索引不感兴趣,代码会容易得多。
为了测试:我对它进行了一些重组。此外,如果您已经知道 $q[$_] eq $s[$_]
,则不必同时检查 $t[$_] eq $s[$_]
和 $t[$_] eq $q[$_]
。如果 $t[$_] eq "+"
,您根本不必进行该检查
#!/usr/bin/env perl
use strict; # These aren't optional!
use warnings; # Always use them!
use 5.01; # for the // operator and say
my @t = qw(a b c d e + g h + j k m n l + h +);
my @q = qw(a b c d e f g h i j k l m l j h h);
my @s = qw(a b c d e f g h k j k l m l j h h);
my ($start);
sub print_interval{
my $end = shift;
printf((' 'x(8+$start-$end)). # inserting the whitespaces
"[%2d-%-2d]\n", $start, $end);
}
foreach (0..$#q){
my ($te, $qe, $se) = ($t[$_], $q[$_], $s[$_]); # just shorthands
if($qe eq $se && ($te eq "+" || $te eq $qe)){
$start //= $_; # if not set, set it to the current index
print $te;
}elsif (defined $start){
print_interval($_-1);
undef $start;
}
}
if (defined $start){
# if we are still in an interval at the end,
# we'll have to print that too.
print_interval($#q)
}
如果您对定义检查感到不舒服,您也可以将 $start
设置为 -1
并检查 0 <= $start
.
这是一个使用中间对象并将结果保存在数组中的解决方案,这样可以更好地格式化并且代码结构更好:
# … strict, warnings, array declarations
my ($res,@results);
foreach (0..$#q){
my ($te, $qe, $se) = ($t[$_], $q[$_], $s[$_]);
if($qe eq $se && ($te eq "+" || $te eq $qe)){
$res = {start => $_, string => ''} unless defined $res;
$res->{string} .= $te;
}elsif (defined $res){
$res->{end} = $_-1;
push @results, $res;
undef $res;
}
}
if (defined $res){ # still in interval
$res->{end} = $#q;
push @results, $res;
}
printf "%-9s[%2d-%-2d]\n", @{$_}{qw|string start end|} for @results;
#!/usr/bin/perl
use strict;
use warnings;
my @t = qw(a b c d e + g h + j k m n l + h +);
my @q = qw(a b c d e f g h i j k l m l j h h);
my @s = qw(a b c d e f g h k j k l m l j h h);
my @current_interval = (); #will store the interval we are currently working on
my @intervals = (); #keeps track of all those intervals
for(0 .. $#t){
if($q[$_] eq $s[$_] and ($q[$_] eq $t[$_] or $t[$_] eq '+')){
push(@current_interval, $_);
}
else{
if(@current_interval){
push(@intervals, [$current_interval[0], $current_interval[$#current_interval]]);
@current_interval = ();
}
}
}
#when exiting the loop we dont want to lose our current interval!
if(@current_interval){
push(@intervals, [$current_interval[0], $current_interval[$#current_interval]]);}
#print intervals
for (@intervals){
my @c = @{$_};
print $c[0],"\t",$c[1],"\n";
}
我为你找到了间隔时间。
请注意,我添加了 "use strict; use warnings" - 在将此解决方案添加到您的项目之前。
你好蒂姆
@t = qw(a b c d e + g h + j k m n l + h +);
@q = qw(a b c d e f g h i j k l m l j h h);
@s = qw(a b c d e f g h k j k l m l j h h);
foreach (0..$#q){
if($t[$_] eq ($q[$_] && $s[$_])){
print "$t[$_]";
}
print "$t[$_]-$t[$_]\n";
elsif($t[$_] eq '+' && $q[$_] eq $s[$_]){
print"$t[$_]";
}
else{
print "\n";
}
}
预期输出:
abcde+gh [1-8]
jk [10-11]
l+h+ [14-17]
此处@t
基于同时匹配@q
和@s
,打印区间也基于@t
。
我无法获得不匹配的间隔。请给我一个好的解决方案
您的代码存在您在第 4 次编辑时引入的语法错误。您不能将任何代码放在 if
的块及其 elseif
之外。如果我没理解错的话,您想知道数组 @q
、@s
和 @t
何时排列,其中 @t
允许使用 '+'
作为通配符.
这是一种解决方案。它使用 $start
变量来检查我们是否在区间内并存储开头。如果我们处于区间或数组的末尾。我们打印间隔长度。可能有更好的方法来格式化它。最好的办法是引入更复杂的临时对象。如果您对区间开始和结束的索引不感兴趣,代码会容易得多。
为了测试:我对它进行了一些重组。此外,如果您已经知道 $q[$_] eq $s[$_]
,则不必同时检查 $t[$_] eq $s[$_]
和 $t[$_] eq $q[$_]
。如果 $t[$_] eq "+"
#!/usr/bin/env perl
use strict; # These aren't optional!
use warnings; # Always use them!
use 5.01; # for the // operator and say
my @t = qw(a b c d e + g h + j k m n l + h +);
my @q = qw(a b c d e f g h i j k l m l j h h);
my @s = qw(a b c d e f g h k j k l m l j h h);
my ($start);
sub print_interval{
my $end = shift;
printf((' 'x(8+$start-$end)). # inserting the whitespaces
"[%2d-%-2d]\n", $start, $end);
}
foreach (0..$#q){
my ($te, $qe, $se) = ($t[$_], $q[$_], $s[$_]); # just shorthands
if($qe eq $se && ($te eq "+" || $te eq $qe)){
$start //= $_; # if not set, set it to the current index
print $te;
}elsif (defined $start){
print_interval($_-1);
undef $start;
}
}
if (defined $start){
# if we are still in an interval at the end,
# we'll have to print that too.
print_interval($#q)
}
如果您对定义检查感到不舒服,您也可以将 $start
设置为 -1
并检查 0 <= $start
.
这是一个使用中间对象并将结果保存在数组中的解决方案,这样可以更好地格式化并且代码结构更好:
# … strict, warnings, array declarations
my ($res,@results);
foreach (0..$#q){
my ($te, $qe, $se) = ($t[$_], $q[$_], $s[$_]);
if($qe eq $se && ($te eq "+" || $te eq $qe)){
$res = {start => $_, string => ''} unless defined $res;
$res->{string} .= $te;
}elsif (defined $res){
$res->{end} = $_-1;
push @results, $res;
undef $res;
}
}
if (defined $res){ # still in interval
$res->{end} = $#q;
push @results, $res;
}
printf "%-9s[%2d-%-2d]\n", @{$_}{qw|string start end|} for @results;
#!/usr/bin/perl
use strict;
use warnings;
my @t = qw(a b c d e + g h + j k m n l + h +);
my @q = qw(a b c d e f g h i j k l m l j h h);
my @s = qw(a b c d e f g h k j k l m l j h h);
my @current_interval = (); #will store the interval we are currently working on
my @intervals = (); #keeps track of all those intervals
for(0 .. $#t){
if($q[$_] eq $s[$_] and ($q[$_] eq $t[$_] or $t[$_] eq '+')){
push(@current_interval, $_);
}
else{
if(@current_interval){
push(@intervals, [$current_interval[0], $current_interval[$#current_interval]]);
@current_interval = ();
}
}
}
#when exiting the loop we dont want to lose our current interval!
if(@current_interval){
push(@intervals, [$current_interval[0], $current_interval[$#current_interval]]);}
#print intervals
for (@intervals){
my @c = @{$_};
print $c[0],"\t",$c[1],"\n";
}
我为你找到了间隔时间。 请注意,我添加了 "use strict; use warnings" - 在将此解决方案添加到您的项目之前。
你好蒂姆