0

我遇到了一件简单的事情。我需要比较两个文件并只写入两者之间不匹配的模式。

我的第一个文件如下所示:

1 A A
2 A B
3 C D
4 E F
5 G H
6 I L

我的第二个文件如下所示:

A A
A B
C D

我想要的是使用第二个文件中的对列表来选择第一个文件中不匹配的行并将它们打印在输出中。我想要的输出如下所示:

4 E F
5 G H
6 I L

我下面的代码需要改进,我需要你的帮助来做到这一点!

open (FUS, "< $file_1")|| die "Impossible open file 1";
@f = <FUS>;
close (FUS);

open (ALL, "< $file_2")|| die "Impossible open file 2";
@a = <ALL>;
close (ALL);

for ($c=0; $c<=$#a; $c++) {
    chomp ($a[$c]);
    @q = split (/\t/, $a[$c]);
    $qok = $q[0]."\t".$q[1];
    $qko = $q[1]."\t".$q[0];

    for ($t=0; $t<=$#f; $t++) {
        chomp ($f[$t]);
        ($id, $pf1, $pf2) = split (/\t/, $f[$t]);
        $pf_12 = $pf1."\t".$pf2;
        $pf_21 = $pf2."\t".$pf1;

        if ((($qok ne $pf_12) && ($qko ne $pf_12)) || (($qok ne $pf_21) && ($ko ne $pf_21))){
            print "$id\t$pf1\t$pf2\n";
        }
    }
}

这段代码的问题在于循环中的某些东西,这使我获得了错误的结果,而不是想要的结果。

非常欢迎任何建议!

4

3 回答 3

5

grep如果您愿意,这真的很容易做到:

$ grep -Fvf b.txt a.txt
4 E F
5 G H
6 I L

-F意思是“固定字符串”,-v意思是“反转匹配”,-f意思是“从文件中读取模式,每行一个”。

于 2013-08-06T11:37:03.657 回答
1

实现此目的的常用方法是将第二个文件存储在哈希中:

open my $ALL, '<', $file_2 or die "$file_2 : $!";

my %hash;
while (<$ALL>) {
    chomp;
    $hash{$_} = 1;
}

open my $FUS, '<', $file_1 or die "$file_1 : $!";
while (<$FUS>) {
    my ($columns) = / (.*)/;
    print unless exists $hash{$columns};
}
于 2013-08-06T11:26:52.983 回答
1

如果您的文件不是太大,我建议使用哈希:

1) 使用字符串所需的匹配部分作为键填充 %hash_a。读取文件后,此哈希将具有以下内容:

%hash_a = (
'A A' => '1 A A',
'A B' => '2 A B',
...
'I L' => '6 I L'
);

2)迭代第二个文件,并从 %hash_a 中删除正确的键:

$key =<$file>;
chomp $key;
delete $hash_a{$key};

3) 在 %hash_a 上打印剩余的键

另外,我建议你:

  • 把它放在脚本的开头:
use strict;
use warnings;
  • 使用现代方法处理文件:
open my $FUS, '<', $file_1 or die "Cannot open $file_1: $!";
于 2013-08-06T11:30:39.790 回答