1

我知道使用 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 条这样的线

文件2

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

4 回答 4

2

您必须先读入其中一个文件。然后您可以匹配另一个文件的每一行的内容。我使用firstList ::Util来做到这一点。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;
}

我强烈建议您在所有程序中使用strictand 。warnings它们都可以帮助您发现小的、微妙的错误。以更具描述性的方式命名变量也是一个好主意。数组命名@1@2非常糟糕。我很难理解哪个变量做了什么。

于 2012-11-21T08:45:48.963 回答
2

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

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

你知道内循环的代码多久执行一次吗?scalar(@2) * scalar(@1)次,在您的示例中约为 400 万次。这就是为什么你的文件变得那么大的原因。将内循环替换为

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

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

编码风格!啊!:D

这种编码风格是从上个千年开始的!让我添加一些说明如何使您的代码更安全、更易读和更可调试:

  • 总是use strict;use warnings;。许多错误可以通过这种方式尽早发现。
  • 不要使用全局(包)变量,这对strictures 没有那么诱人。使用词法变量 ( my @lines = ...)。
  • 使用正确的变量名:@1不是很有帮助。事实上,使用它的单个元素 ( $1[42]) 看起来很混乱,因为$1Perl 的正则表达式捕获变量。它不必非常富有诗意。一个简单的@lines会工作,但甚至@gargravarr@1.
  • 不需要时不要使用字符串插值。可接受的用途:"Hi $name, what's up?". 坏:print "$_"。只需使用print $_.
  • 使用空白。if($_=~m/^$two.+/)看起来像线路噪音。为了进行比较,请看这段手工制作的史诗般美丽的 Perl 代码:
foreach 我的 $line (@lines) {
    打印$差异$行
        if $line =~ /^$prefix.*/;
}

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

my $matched = 0;

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

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

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

于 2012-11-21T10:41:31.090 回答
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 是您的文件。

于 2012-11-21T09:01:52.997 回答
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";
}
于 2012-11-26T06:39:07.257 回答