Выборочное объединение содержимого файла

Мне нужно совместить два файла и печатать только те строки, которые после определенного символа не выполняются только элементами из одного из файлов.

Например, у меня есть два файла, которые выглядят следующим образом:

1A00.pdb_HEM_COA 1A01.pdb_HEM 1A05.pdb_IPM 1A0F.pdb_GTS_4CA 1A0G.pdb_PMP 1A0I.pdb_2CP

и это:

COA 2CP 3CP 3HC 4CA 4CO

Я хочу их сопоставить, и если окажется, что сначала _ следует только элементы из второго файла, тогда не печатайте их (пример 1A0I.pdb_2CP). Если в других строках кажется, что _ следует за некоторым другим элементом, но также элементом из второго файла, а затем просто удаляет этот элемент, который является общим в обоих файлах, но печатает строку (например, 1A00.pdb_HEM_COA, а печатная строка должна быть как 1A00.pdb_HEM).

Кто-нибудь знает, как это сделать?

0
задан 25 January 2018 в 11:53

3 ответа

Вы можете создать хеш perl из строк второго файла

#!/usr/bin/perl -w

use strict;

BEGIN{ $/ = $\ = "\n"; }

my $stringsfile = shift @ARGV;
open(my $fh, '<:encoding(UTF-8)', $stringsfile)
  or die "Could not open file '$stringsfile' $!";

my %h;

while (defined($_ = <$fh>)) {
    chomp $_;
    $h{$_} = 1;
}

, а затем разделить строки первого (и последующих) файлов на дефисные поля, grep для этих полей которые не находятся в хеше, и присоедините их все вместе и напечатайте, если grep возвращает что-либо:

while (defined($_ = <ARGV>)) { 
    chomp $_;
    my ($x, @F) = split(/_/, $_, 0);
    my @y = grep({not $h{$_};} @F);
    print join('_', $x, @y) if @y;
}

Использование:

$ ./foo.pl file2 file1
 1A00.pdb_HEM
 1A01.pdb_HEM
 1A05.pdb_IPM
 1A0F.pdb_GTS
 1A0G.pdb_PMP

Примечание: если потенциальные совпадения находятся в конце, то с помощью awk существует гораздо более простой подход:

awk '
  BEGIN{OFS=FS="_"} 
  NR==FNR {a[$0]++; next} 
  {while ($NF in a) NF--} 
  NF>1 {print}
' file2 file1

. Для выборочных данных в вашем вопросе оба подхода создают одинаковый вывод.

0
ответ дан 22 May 2018 в 15:19
  • 1
    Потенциальные совпадения не должны быть в конце каждой строки. Этот скрипт perl работал отлично. Спасибо! – djordje 29 January 2018 в 08:09
  • 2
    Я только что проверил его еще раз, и скрипт не смог удалить эти строки всякий раз, когда появляется только элемент из второго списка. Когда я использую эти примеры из вопроса, он работает proprely, но когда я включаю 100 больше elements в file2, он не обрабатывается. Может ли проблема size файла? У моего file2 есть 160 elements и file1 вокруг 100 lines .. – djordje 29 January 2018 в 14:16
  • 3
    AFAIK нет предела линии - он работает для меня в последней строке тестового файла - я предполагаю, что некоторые из ваших строк имеют завершающие пробельные символы. – steeldriver 29 January 2018 в 16:24
  • 4
    Да, он также отлично работает для меня на этих данных из вопроса, но имеет проблемы с большими данными ... это, конечно, не что-то о скрипте, а о входных файлах. Спасибо за это умное предложение. Я удалю все пробелы для ввода, а затем попробую! – djordje 29 January 2018 в 17:02

Вы можете создать хеш perl из строк второго файла

#!/usr/bin/perl -w use strict; BEGIN{ $/ = $\ = "\n"; } my $stringsfile = shift @ARGV; open(my $fh, '<:encoding(UTF-8)', $stringsfile) or die "Could not open file '$stringsfile' $!"; my %h; while (defined($_ = <$fh>)) { chomp $_; $h{$_} = 1; }

, а затем разделить строки первого (и последующих) файлов на дефисные поля, grep для этих полей которые не находятся в хеше, и присоедините их все вместе и напечатайте, если grep возвращает что-либо:

while (defined($_ = <ARGV>)) { chomp $_; my ($x, @F) = split(/_/, $_, 0); my @y = grep({not $h{$_};} @F); print join('_', $x, @y) if @y; }

Использование:

$ ./foo.pl file2 file1 1A00.pdb_HEM 1A01.pdb_HEM 1A05.pdb_IPM 1A0F.pdb_GTS 1A0G.pdb_PMP

Примечание: если потенциальные совпадения находятся в конце, то с помощью awk существует гораздо более простой подход:

awk ' BEGIN{OFS=FS="_"} NR==FNR {a[$0]++; next} {while ($NF in a) NF--} NF>1 {print} ' file2 file1

. Для выборочных данных в вашем вопросе оба подхода создают одинаковый вывод.

0
ответ дан 17 July 2018 в 22:16

Вы можете создать хеш perl из строк второго файла

#!/usr/bin/perl -w use strict; BEGIN{ $/ = $\ = "\n"; } my $stringsfile = shift @ARGV; open(my $fh, '<:encoding(UTF-8)', $stringsfile) or die "Could not open file '$stringsfile' $!"; my %h; while (defined($_ = <$fh>)) { chomp $_; $h{$_} = 1; }

, а затем разделить строки первого (и последующих) файлов на дефисные поля, grep для этих полей которые не находятся в хеше, и присоедините их все вместе и напечатайте, если grep возвращает что-либо:

while (defined($_ = <ARGV>)) { chomp $_; my ($x, @F) = split(/_/, $_, 0); my @y = grep({not $h{$_};} @F); print join('_', $x, @y) if @y; }

Использование:

$ ./foo.pl file2 file1 1A00.pdb_HEM 1A01.pdb_HEM 1A05.pdb_IPM 1A0F.pdb_GTS 1A0G.pdb_PMP

Примечание: если потенциальные совпадения находятся в конце, то с помощью awk существует гораздо более простой подход:

awk ' BEGIN{OFS=FS="_"} NR==FNR {a[$0]++; next} {while ($NF in a) NF--} NF>1 {print} ' file2 file1

. Для выборочных данных в вашем вопросе оба подхода создают одинаковый вывод.

0
ответ дан 23 July 2018 в 22:55

Другие вопросы по тегам:

Похожие вопросы: