如何从两个文本文件中提取不匹配的行?

时间:2012-11-21 07:13:03

标签: perl cmd

我知道使用perl提取匹配行但我想要两个不匹配的文件中的行,即它们对于两个文本文件中的文件是唯一的。

文件1

one|E2027.1|073467|66   ATGCTATGTTTTGCTAAT  
one|E2002.1|073405|649  ATGAAAGCTTTAAAGAAA  
one|E2001.1|734704|201  ATGTTTTCAGGTATTATA  
one|E2025.1|073468|204  ATGAAACAGAAATATATT  
one|E2028.1|073431|578  ATGTTATTTAATTATGGT  
one|E2040.1|073743|862  ATGATTTATCCTAATAAT   

.........〜2000这样的行

file2

one|E2027.1|073467|66  
one|E5005.5|000005|005  
one|E2001.1|734704|201  
one|E2025.1|073468|204  
one|E2028.1|073431|578  
one|E2040.1|073743|862    

.........〜2000这样的行

如何使用perl或cmd命令提取不匹配的行? 这里例如文件2的第2行对于文件2是唯一的..... !!!

这是我到目前为止所拥有的

foreach(@2) {
    @org=split('\t',$_);
    chomp($two=$_);
    foreach(@1) {
        if($_=~m/^$two.+/) {
            print OUT1 "$_";
        } else {
            print OUT2 "$_";
        }
    }
}

但是输出提供GB数据。

4 个答案:

答案 0 :(得分:2)

您必须首先阅读其中一个文件。然后,您可以匹配其他文件的每一行的内容。我使用了来自List::Utilfirst来做到这一点。 grep也很好,但是first在找到第一次出现后停止,这样可以节省大文件的时间。

use strict;
use warnings;
use List::Util qw(first);
use 5.014;

my $file1 = <<"FILE1";
one|E2027.1|073467|66\tATGCTATGTTTTGCTAAT
one|E2002.1|073405|649\tATGAAAGCTTTAAAGAAA
one|E2001.1|734704|201\tATGTTTTCAGGTATTATA
one|E2025.1|073468|204\tATGAAACAGAAATATATT
one|E2028.1|073431|578\tATGTTATTTAATTATGGT
one|E2040.1|073743|862\tATGATTTATCCTAATAAT
FILE1

my $file2 = <<"FILE2";
one|E2027.1|073467|66
one|E5005.5|000005|005
one|E2001.1|734704|201
one|E2025.1|073468|204
one|E2028.1|073431|578
one|E2040.1|073743|862
FILE2

my @file1_content = map { (split(/\t/))[0] } split /\n/, $file1;

foreach my $line (split /\n/, $file2) {
  chomp $line; # we need that because the split above is just a filler
  next if first { $_ eq $line } @file1_content;
  say $line;
}

我强烈建议您在所有程序中使用strictwarnings。他们都帮助你找到小的,微妙的错误。以更具描述性的方式命名变量也是一个好主意。名为@1@2的数组非常糟糕。我无法理解哪个变量做了什么。

答案 1 :(得分:2)

只是为了帮助您改进代码:

foreach(@2) {
    @org=split('\t',$_);
    chomp($two=$_);
    foreach(@1) {
        if($_=~m/^$two.+/) {
            print OUT1 "$_";
        } else {
            print OUT2 "$_";
        }
    }
}

你知道内循环代码执行的频率吗? scalar(@2) * scalar(@1)次,在你的例子中约为4百万。这就是为什么你的文件变得那么大的原因。用

替换内环
$matched=0;
foreach(@1) {
    if($_=~m/^$two.+/) {
        $matched=1;
        last;
    }
}
if($matched) {
    print OUT1 $_;
} else {
    print OUT2 $_;
}

内部循环现在跟踪匹配并且只在外部循环中写入文件。 请注意,我尝试适应您的编码风格!

CODING STYLE!哎呀! :d

编码风格从上一个千年开始!让我添加一些注释,让您的代码更安全,更可读,更可调试:

  • 始终use strict;use warnings;。很多错误都可以尽早找到。
  • 不要使用全局(包)变量,这不是引用strict ures的。使用词汇变量(my @lines = ...)。
  • 使用正确的变量名称:@1不是很有用。实际上,使用其单个元素($1[42])看起来非常混乱,因为$1是Perl的正则表达式捕获变量。它不一定非常富有诗意。一个简单的@lines可以使用,但即使@gargravarr也优于@1
  • 不要在不需要时使用字符串插值。可接受的使用:"Hi $name, what's up?"。不好:print "$_"。只需使用print $_
  • 使用空格。 if($_=~m/^$two.+/)看起来像线路噪音。为了进行比较,请看看这个手​​工制作的美丽Perl代码片段:
foreach my $line (@lines) {
    print $differences $line
        if $line =~ /^$prefix.*/;
}

因此,让我们尝试重写该代码:

my $matched = 0;

foreach my $line (@lines) {
    if ($line = ~/^$two.+/) {
        $matched=1;
        last;
    }
}

if ($matched) {
    print OUT1 $_;
} else {
    print OUT2 $_;
}

现在感觉好多了! :) 知道你在做什么!不要只是复制'n'拼贴代码片段。

答案 2 :(得分:0)

#!/usr/bin/perl
use strict;
use warnings;

open my $fh1 ,'<', 'f1' or die $!;
open my $fh2 ,'<', 'f2' or die $!;
chomp(my @ar1=<$fh1>);
chomp(my @ar2=<$fh2>);
close $fh1;
close $fh2;

my @ar3=();
foreach my $x (@ar2) {
   push @ar3, $x if not grep (/^\Q$x\E/,@ar1);
}
print "@ar3";

其中f1和f2是你的文件。

答案 3 :(得分:0)

我得到了这个;如果要比较的数据应该在两个文件中都是单列

use strict;use warnings;
print "Enter file1: ";
chomp($file=<STDIN>);
open(FH,$file);

print"Enter file2: ";
$hspfile=<STDIN>;
open(FH1,$hspfile);

my $list1;
my $list2;
my @list1 =<FH1> ;my @list2 =<FH> ;
print "enter output file1 : ";
$out = <STDIN>;
chomp($out);
open(OUT,">$out");
LIST2: foreach $list2 (@list2){
LIST1: foreach $list1 (@list1){
if ("$list2" eq "$list1") {
next LIST2;
}
}
print OUT"$list2";
}