2017-02-09 3 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 истинный

= Кластерный =
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 верно

Я использую это, чтобы разбить файл, используя но я не знаю, как проверить, если спектр повторяется.

#!/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, в котором я использовал groupby от itertools модуль.

Я предполагаю, что ваш входной файл называется 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 

 Смежные вопросы

  • Нет связанных вопросов^_^