使用 Perl 根据列比较三个文件

使用 Perl 根据列比较三个文件

我有三个文件,我需要将文件 1 的第一列与文件 2 的第一列匹配,然后将文件 1 的第二列与文件 3 的第一列匹配。

  • 文件 1 包含以下行以及更多行:

    • fji01dde AIDJFMGKG  
      dlp02sle VMCFIJGM
      cmr03lspCKEIFJ
      
  • 文件 2 包含以下行以及更多行:

    • fji01dde 25 30  
      dlp02sle 40 50  
      cmr03lsp 60 70  
      
  • 文件 3 包含:

    • 爱德吉FMGKG  
      CKEIFJ  
      
  • 我的预期输出是:

    • fji01dde AIDJFMGKG 25 30  
      cmr03lsp CKEIFJ 60 70  
      
    • 等等...

  • 我只想要所有三个文件中常见的行,但是当我运行时......

    • #!/usr/bin/env perl
      use strict;
      use warnings;
      my %data;
      
      while (<>) {  
          my ( $key, $value ) = split;  
          push( @{ $data{$key} }, $value );  
      }  
      
      foreach my $key ( sort keys %data ) {  
          if ( @{ $data{$key} } >= @ARGV ) {  
          print join( "\t", $key, @{ $data{$key} } ), "\n";  
          }    
      }
      
    • 我的结果是...

    • 爱德吉FMGKG  
      CKEIFJ  
      fji01dde 25  
      dlp02sle 40  
      cmr03lsp 60
      

有任何想法吗?提前致谢!

答案1

while(<>)您的脚本的主要问题是,当循环结束时,@ARGV 为空。您需要在循环之前获取参数计数。请记住,perl 数组是从零开始的,因此您必须从计数中减去 1。

这是一个固定版本,可以生成您请求的输出。

$ cat compare.pl 
#!/usr/bin/perl
use strict;
use warnings;

my $numargs=@ARGV-1;
my %data=();

while (<>) {  
    my ( $key, $value ) = split;  
    push( @{ $data{$key} }, $value );  

}  

foreach my $key ( sort keys %data ) {  
    if ( @{ $data{$key} } >= $numargs ) {  
    print join( "\t", $key, @{ $data{$key} } ), "\n";  
    }  
}

$ ./compare.pl file1 file2 file3
cmr03lsp    CKEIFJ  60
dlp02sle    VMCFIJGM    40
fji01dde    AIDJFMGKG   25

答案2

交叉发布问题,因此交叉发布答案:

好的,看看它 - 你的问题在于split- 因为默认情况下,它会在空格上分割。按照这个标准,你的第二个文件有 3 个字段,而不是两个。

而且 - 你实际上并没有交叉引用相同的东西,所以你的while ( <> ) {循环不会起作用。

  • 在文件 1 中 - 您想要检查价值
  • 在 file2 中,您正在检查键(并附加值)。
  • 在 file3 中,你没有值,只有一个键。

因此考虑到这一点:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

#read file1 into a hash - but invert is it's value => key instead:
#          'CKEIFJ' => 'cmr03lsp',
# etc.  
open( my $file1, '<', "file1.txt" ) or die $!;
my %file1_content = map { reverse split } <$file1>;
close($file1);

print Dumper \%file1_content;

#read file 2 - read keys, store the values. 
#split _2_ fields, so we keep both numbers as a substring:
#e.g.:
#          'cmr03lsp' => '60 70
#',

open( my $file2, '<', "file2.txt" ) or die $!;
my %file2_content = map { split( " ", $_, 2 ) } <$file2>;
close($file2);

print Dumper \%file2_content;    

#then iterate file 3, checking if:
#file1 has a matching 'key' (but inverted - as a value) 
#file2 has a cross reference. 
open( my $file3, '<', "file3.txt" ) or die $!;
while ( my $line = <$file3> ) {
    chomp $line;
    if (    $file1_content{$line}
        and $file2_content{ $file1_content{$line} } )
    {
        print
            "$file1_content{$line} $line $file2_content{$file1_content{$line}}";
    }
}
close($file3);

这将打印(不包括“dumper”输出):

fji01dde AIDJFMGKG 25 30
cmr03lsp CKEIFJ 60 70

相关内容