-2

我目前正在尝试在 perl 脚本中合并两个不同的文本文件- 但是它比这更复杂一些。

问题(为了便于解释略有改动):

我有两个不同的文本文件,一个命名dog1.txt一个命名dog2.txt(如下所示)。

dog1.txt
    poodle     8888
    jackrussel    5743
    beagle     6784

dog2.txt 
    spaniel    9843
    poodle    3756
    germanshepard    3267
    beagle    3478  

如您所见,poodle 和 beagle 都包含在两个文本文件中,但与它们关联的四位代码不同。

我想要的是创建一个将这两个文件合并在一起的新文件,如果有任何重复项,例如贵宾犬和比格犬,我希望新文件包含与贵宾犬和比格犬相关的四位数字来自 dog1.txt 文件而不是 dog2.txt。

新文件需要如下所示(狗名的顺序无关紧要,与它们相关的数字需要正确):

final_dog.txt
    poodle    8888
    germanshepard    3267
    jackrussel    5743
    beagle    6784
    spaniel    9843

我尝试了许多不同的解决方案,但没有一个能像我需要的那样可靠地工作。

非常感谢任何帮助,谢谢

4

3 回答 3

4

您基本上想打印遇到的第一个实例。因此,您可以使用标准习语来删除重复项。

perl -lane'print if !$seen{$F[0]}++' dog1.txt dog2.txt >final_dog.txt

这种方法使用的内存最少。它还尽可能早地开始产生输出(如果您正在管道输出,则很有用)。


为了满足新的要求,使用

perl -lane'print if @F==2 && $F[1]=~/^\d+\z/ && !$seen{$F[0]}++' \
   dog1.txt dog2.txt >final_dog.txt
于 2012-12-04T23:49:56.533 回答
0

作为一个单行:

perl -MData::Dumper -lwe '
           $d = pop;             # save filename for later
           %d = map split, <>;   # process dog1.txt
           push @ARGV, $d;       # put the second file name back
           while (<>) {          # add new entries, unless already defined
               my ($dog,$num) = split; $d{$dog} //= $num; 
           } 
           print Dumper \%d' dog1.txt dog2.txt

输出:

$VAR1 = {
          'poodle' => '8888',
          'spaniel' => '9843',
          'germanshepard' => '3267',
          'beagle' => '6784',
          'jackrussel' => '5743'
        };

@ARGV此解决方案使用菱形运算符对参数进行的隐式打开<>//=定义或赋值运算符不会覆盖已经定义的值。

正如 ikegami 巧妙地指出的那样,可以通过颠倒参数来消除检查值的必要性。那么这变得非常简单:

perl -MData::Dumper -lwe '
           %d = map split, <>; 
           print Dumper \%d' dog2.txt dog1.txt   # note reversed args

我将把打印语句留给你,因为你没有指定你的文件是制表符分隔的还是其他的。但是您可能会执行以下操作:

print join "\t", $_, $d{$_} for keys %d;      # tab separated
printf "%-20s %s\n", $_, $d{$_} for keys %d;  # fixed width

请注意,这是一种破坏性的解决方案,与 ikegami 保留原始格式的答案不同。

于 2012-12-04T23:44:24.743 回答
-1

该解决方案可以满足您的要求,此外它还满足每行值可能包含空格的情况。

use strict;
use warnings;

my %data;

for my $file (qw/ dog2.txt dog1.txt /) {

  open my $fh, '<', $file or die $!;

  while (<$fh>) {
    $data{$1} = $2 if /(\S+)\s+(\S(?:.*\S)?)/;
  }
}

while (my ($key, $val) = each %data) {
  print "$key $val\n";
}

输出

poodle 8888
spaniel 9843
germanshepard 3267
beagle 6784
jackrussel 5743
于 2012-12-05T01:08:15.937 回答