1

我想使用 grep 两次:

1)我有来自 tsv 文件的二维数组,我想使用 grep 查找行并复制下一列的内容。

例如:

文件:

red     cat
blue    dog

代码:

open (LIST, "file.tsv");
my @list = <LIST>;
my @grepd = grep /blue/ @list;
print @grepd;

结果 perl 打印"blue dog"我希望他只打印"dog"

2)我有列表,我想使用 grep 查找短语,然后复制它旁边的对象。

例如:

my @list = ('red', 'cat','blue', 'dog');
my @grepd = grep /red/ @list;
print @grepd;

结果 perl 打印"red"我可以让他打印"cat"吗?或者更一般地打印查询对象旁边的对象?

非常感谢!

4

2 回答 2

1

关于“<em>我可以grep下一个元素吗”这个问题——让我们编写一个函数来为我们做这件事。

首先,我们遍历除最后一个以外的所有索引。当索引处的元素满足条件时,我们会记住下一个元素。我们可以这样写:

my @input = ...;
my @output = map  { $input[$_ + 1]                 }  # get the next element
             grep { $input[$_] =~ /some condition/ }  # grep all interesting indices
             0 .. $#input - 1;  # all indices but the last

或等效地:

my @input = ...;
my @output;

for my $i (0 .. $#input - 1) {
  push @output, $input[$i + 1] if $input[$i] =~ /some condition/;
}

我们现在想把它抽象成一个函数。为此,我们将回调(或:匿名函数)作为第一个参数。然后我们将调用这个函数并$_设置为当前元素。我们必须在设置它之前本地化该变量以避免污染该函数的任何调用者:

sub grepnext (&@) {
  my $callback = shift;
  # input is @_
  my @out;
  for my $i (0 .. $#_ - 1) {
    # localize $_ and set it to the current element
    local $_ = $_[$i];
    push @out, $_[$i + 1] if $callback->();
  }
  return @out;
}

我们现在可以这样做:

my @after_red = grepnext { /red/ } qw(red cat blue dog);

grepnext以一种允许我们像上面那样调用它的方式声明。这使用了一个(&@) 原型。原型是一种功能,它允许我们在某些情况下更改函数调用的解析。它们非常强大,通常不应该使用。它们与命名参数无关,不能用于任何参数验证。此外,子例程必须在对其进行任何调用之前声明。

没有原型,我们必须使用这种形式:

my @after_red = grepnext sub{ /red/ }, qw(red cat blue dog);

无论哪种方式,@after_red现在都将正确包含一个元素,即"cat".

于 2013-10-20T10:52:52.193 回答
0

如果我正确理解您的目的,您可以更好地使用hash

#!/usr/bin/perl
use warnings;
use strict;

my %hash;
open my $fread, '<', "file.tsv" or die $!;
foreach (<$fread>) {
    push @{$hash{$1}}, $2 if /(\w+)\s+(\w+)/;
}
close $fread;

print @{$hash{'blue'}};
print @{$hash{'red'}};

输出:

dog
cat 

1)使用regex捕获元素$1而不是grep

open my $fread, '<', "file.tsv" or die $!;
my @list = <$fread>;
my @grepd;
foreach (@list) {
    push @grepd, $1 if /blue\s+(\w+)/;
}
print @grepd;
close $fread;

输出:

dog

2) 使用shift

my @list = ('red', 'cat','blue', 'dog');
my @grepd;
while ($_ = shift @list) {
    push @grepd, shift @list if /red/;
}
print @grepd;

输出:

cat
于 2013-10-20T08:04:45.707 回答