2017-02-09 57 views
0

我試圖找到一個很好的方式來執行此操作,但不幸的是我沒有找到一個。根據模式刪除文件中的重複行

我用這個格式文件的工作:

=集羣=
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22491.xml;頻譜= 1074真
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml;頻譜= 2950真

=羣集=
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml;頻譜= 1876真
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml;頻譜= 3479真
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml;頻譜= 3785真

=羣集=
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22493.xml;頻譜= 473真
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22493.xml;頻譜= 473真

正如你所看到的,除了最後一個,每個SPEC行都是不同的,其中字符串譜圖的編號重複。 我想要做的是將模式=Cluster=之間的每一塊信息,並檢查是否有頻譜值重複行。如果有多行重複,則除去一行。

輸出文件應該是這樣的:

=羣集=
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22491.xml;頻譜= 1074真
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml;頻譜= 2950真

= Cluster =
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml; spectrum = 1876 true
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml; spectrum = 3479 true
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22498.xml;頻譜= 3785真

=羣集=
SPEC PRD000681; PRIDE_Exp_Complete_Ac_22493.xml;頻譜= 473真

我使用此使用分割文件模式,但我不知道如何檢查是否有頻譜重複。

#!/usr/bin/perl 

undef $/; 
$_ = <>; 
$n = 0; 

for $match (split(/(?==Cluster=)/)) { 
     open(O, '>temp' . ++$n); 
     print O $match; 
     close(O); 
} 

PD:我用Perl的,因爲這對我來說更容易,但我知道蟒蛇爲好。

+2

重複的行連續? – Toto

回答

1

像這樣的東西會刪除重複行(全局遍歷文件)。

#!/usr/bin/perl 

use warnings; 
use strict; 

my %seen; 

while (<>) { 
    next if (m/SPEC/ and $seen{$_}++); 
    print; 
} 

如果您想更具體的瞭解頻譜值,例如:

next if (m/spectrum=(\d+)/ and $seen{$1}++); 

當你分割你的集羣,你可以做的相當類似,只是:

if ($line =~ m/==Cluster==/) { 
    open ($output, ">", "temp".$count++); 
    select $output; 
    } 

這將設置默認的「打印」位置$output(你需要聲明它的循環之外了。

您還應該:

  • use strict;use warnings;
  • 避免讀取<>$_,這是不必要的。但是,如果你不得不去$block = do { local $/; <> };,那一般會更好。然後$block =~ m/regex/
  • 使用詞法文件句柄:open (my $output, '>', 'filename') or die $!;
  • 檢查開放的返回碼(or die $!通常就足夠了)。

因此,這將是這樣的:

#!/usr/bin/perl 

use warnings; 
use strict; 

my %seen; 
my $count = 0; 
my $output; 

while ( <>) { 
    next if (m/spectrum=(\d+)/ and $seen{$1}++); 
    if (m/==Cluster==/) { 
    open ($output, ">", "temp".$count++) or die $!; 
    select $output; 
    } 
    print; 
} 
+0

一個愚蠢的問題。如何刪除分號字符在'next if'之前和生成新文件之後複製?我正在考慮使用'$ str =〜s /; + /;/g;'但我真的不知道如何添加到您的代碼中。 謝謝! – Enrique

+0

如果沒有指定'=〜',那麼默認的操作是'$ _'或當前塊。所以你所需要的只是's /; + /;/g;'而且這樣做。 – Sobrique

0

如果重複的行是連續的,你可以使用這個perl的oneliner:

perl -ani.back -e 'next if defined($p) && $_ eq $p;$p=$_;print' file.txt 

原始文件的備份與擴展.back

+0

或者只使用['uniq'](https://linux.die.net/man/1/uniq)命令。 – dolmen

+0

感謝downvotes!這個答案有什麼問題? – Toto

+0

@Toto不知道...我給你一個;) – Enrique

1

您也可以使用此python腳本,其中我使用groupbyitertools模塊。

我假設你的輸入文件叫做f_input.txt,輸出文件叫new_file.txt

from itertools import groupby 

data = (k.rstrip().split("=Cluster=") for k in open("f_input.txt", 'r')) 
final = list(k for k,_ in groupby(list(data))) 

with open("new_file.txt", 'a') as f: 
    for k in final: 
     if k == ['','']: 
      f.write("=Cluster=\n") 
     elif k == ['']: 
      # write '\n\n' in Windows and '\n' in Linux (tested only in Windows!) 
      f.write("\n\n") 
     else: 
      f.write("{}\n".join(k)) 

輸出文件new_file.txt將類似於您所需的輸出。

+0

這項工作也是,但是這個腳本也刪除了SPEC。我只是想刪除重複的行,而不是重複的單詞。 – Enrique

0

任務似乎很容易沒有需要Perl/Python的:使用uniq命令刪除相鄰的重複行:

$ uniq <input.txt> output.txt