如何根据 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" - 在将此解决方案添加到您的项目之前。

你好蒂姆