使用perl在两个文件之间写入不匹配的元素

时间:2013-08-06 11:18:23

标签: perl

我遇到了一个简单的问题。我需要比较两个文件,只写出两者之间不匹配的模式。

我的第一个文件如下:

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";
        }
    }
}

这段代码的问题在循环中会导致我得到错误的结果而不是所需的结果。

非常欢迎任何建议!

3 个答案:

答案 0 :(得分:5)

如果您愿意,可以使用grep轻松实现:

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

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

答案 1 :(得分: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};
}

答案 2 :(得分:1)

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

1)使用as键填充%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: $!";