如何根据perl中的匹配元素查找间隔?

时间:2015-01-08 08:49:13

标签: 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打印间隔。 我无法获得不匹配的间隔。请给我一个很好的解决方案

2 个答案:

答案 0 :(得分:1)

您的代码在第4次编辑时引入了语法错误。您不能将任何代码放在if的块及其elseif之外。如果我理解正确,您想知道数组@q@s@t何时排队,@t允许'+'作为通配符

这是一个解决方案。它使用$start变量来检查我们是否在一个区间内并存储开头。如果我们在一个间隔或数组的末尾。我们打印间隔长度。可能有更好的格式化方法。最好的方法是引入更复杂的ad-hoc对象。如果您对间隔的开始和结束的索引不感兴趣,代码会更容易。

测试:我稍微重组了一下。此外,如果您已经知道$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;

答案 1 :(得分:1)

#!/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";
}

我得到了你的间隔。 请注意我添加&#34;使用严格;使用警告&#34; - 在将此解决方案添加到项目之前。

问候蒂姆