【问题标题】:perl grep the object next to query objectperl grep 查询对象旁边的对象
【发布时间】:2013-10-20 07:36:26
【问题描述】:

我想使用两次 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" 代替吗?或者更一般地打印查询对象旁边的对象?

非常感谢!

【问题讨论】:

  • “Perl”这个词的词源复杂和有争议的部分原因在于它来源于一个女人的名字。所以问“我怎样才能让改为打印''cat''?”更正确?
  • @mob: -> 脚本

标签: arrays perl grep


【解决方案1】:

关于“我可以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/;
}

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

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

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

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

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

【讨论】:

    【解决方案2】:

    如果我正确理解您的目的,您可以使用 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
    

    【讨论】:

      猜你喜欢
      • 2021-05-03
      • 2017-01-13
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 2014-03-09
      • 1970-01-01
      相关资源
      最近更新 更多