基于模式删除文件中的重复行

2024-09-29 00:22:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图找到一个很好的方法来实现这一点,但不幸的是,我没有找到一个。你知道吗

我正在处理以下格式的文件:

=Cluster=
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22491.xml;spectrum=1074 true
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22498.xml;spectrum=2950 true

=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;spectrum=3785 true

=Cluster=
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22493.xml;spectrum=473 true
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22493.xml;spectrum=473 true

正如您所看到的,每个规范行都是不同的,除了最后一行,其中字符串谱的编号是重复的。 我想做的是获取模式=Cluster=之间的每个信息块,并检查是否有谱值重复的行。如果有多行重复,则删除除一行之外的所有行。你知道吗

输出文件应如下所示:

=Cluster=
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22491.xml;spectrum=1074 true
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22498.xml;spectrum=2950 true

=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;spectrum=3785 true

=Cluster=
SPEC PRD000681;PRIDE_Exp_Complete_Ac_22493.xml;spectrum=473 true

我用这个来分割文件使用的模式,但我不知道如何检查是否有重复频谱。你知道吗

#!/usr/bin/perl

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

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

PD:我使用Perl是因为它对我来说更容易,但我也理解python。你知道吗


Tags: 文件方法true格式match模式xmlac
3条回答

类似这样的操作将删除重复的行(整个文件)。你知道吗

#!/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;
  }

这会将默认的“print”位置设置为$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;
}

如果重复行是连续的,则可以使用以下perl oneliner:

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

原始文件是扩展名为.back的备份

您还可以使用这个python脚本,我在其中使用了来自itertools模块的groupby。你知道吗

我假设您的输入文件名为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将与所需的输出类似。你知道吗

相关问题 更多 >