我有三个文件,我需要将文件 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