От grep к perl: обратное сопоставление по perl - PullRequest
0 голосов
/ 11 февраля 2019

я довольно долго не программирую на Perl, и мне нужно немного нажать кнопку.

Мне нужно сравнить два списка, чтобы сохранить только те строки, которые не совпадают.

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

1   pf1 er2 0,4  
2   pf1 er3 0,56  
3   pf1 er6 0,72365  
4   er3 pf3 0,263
5   pf5 er2 0,28473

Второй файл выглядит так:

pf1 er2
pf1 er3
er2 pf1
er3 pf1

И я хотел бы получить вывод:

3   pf1 er6 0,72365  
4   er3 pf3 0,263
5   pf5 er2 0,28473

Раньше я делал это с помощью grep -Fvf second_file.txt first-file.txt > output.txt

Теперь мне нужно выполнить то же самое в Perl, но я не могу организовать код.

open(HAN, "< $file_1") ||  die "Impossibile aprire il file $file_1";
@r = <HAN>;
close(HAN);
open(RES, "< $file_2") ||  die "Impossibile aprire il file $file_2";
@c = <RES>;
close(RES);

for ($i=0; $i<=$#r; $i++){
    ($num, $id1, $id2, $v) = split (/\t/, $r[$i], 4);

    $ppi1 = $id1."\t".$id2;

    for($t=0; $t<=$#c; $t++){
        ($iid1, $iid2) = split (/ /, $c[$t]);
        $orto1 = $iid1."\t".$iid2;
        $orto2 = $iid2."\t".$iid1;

        if( ($ppi1 ne $orto1) || ($ppi1 ne $orto2) ){
            print "$ppi1\n";
        }
    }
}

Любое предложениеочень добро пожаловать!

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

Это должно работать:

  • читать строки из справочного файла
    • заключать в кавычки содержимое строки, чтобы сделать ее совместимой для составления регулярного выражения из
  • скомпилируйте объединенное регулярное выражение, в котором все OR совпадают
    • , для вашего примера это будет (?:pf1 er2|pf1 er3|er2 pf1|er3 pf1)
  • чтение строк из STDIN
    • выведите строку в STDOUT, если регулярное выражение не соответствует
#!/usr/bin/perl
use strict;
use warnings;

my($reference) = @ARGV;

my $fh;
open($fh, "<". $reference)
    or die "open '${reference}': $!\n";
my @matches;
while (<$fh>) {
    chomp;
    push(@matches, quotemeta);
}
close($fh)
    or die "close '${reference}': $!\n";

# compile combined regex
my $regex = join('|', @matches);
$regex = qr/(?:${regex})/;

while (<STDIN>) {
    print unless $_ =~ $regex;
}

exit 0;

Тестовый вывод:

$ cat dummy1.txt
1   pf1 er2 0,4  
2   pf1 er3 0,56  
3   pf1 er6 0,72365  
4   er3 pf3 0,263
5   pf5 er2 0,28473

$ cat dummy2.txt
pf1 er2
pf1 er3
er2 pf1
er3 pf1

$ perl dummy.pl <dummy1.txt dummy2.txt
3   pf1 er6 0,72365  
4   er3 pf3 0,263
5   pf5 er2 0,28473
0 голосов
/ 11 февраля 2019

Исходя из этих примеров данных, вы хотите исключить строки из первого файла, если второй и третий столбцы соответствуют первому и второму столбцам строки второго файла.Сохранение столбцов второго файла в хэше, а затем проверка наличия этих ключей при чтении первого файла - это простой и очень эффективный способ:

#!/usr/bin/perl
use warnings;
use strict;
use autodie;

my ($data_file, $excludes_file) = @ARGV;

my %excludes;
open my $ex, "<", $excludes_file;
while (<$ex>) {
  chomp;
  my @F = split;
  $excludes{$F[0]}->{$F[1]} = 1;
}

open my $data, "<", $data_file;
while (<$data>) {
  my @F = split;
  print unless exists $excludes{$F[1]}->{$F[2]};
}

Запуск этого файла даст:

$ perl filter.pl file1.txt file2.txt
3   pf1 er6 0,72365  
4   er3 pf3 0,263
5   pf5 er2 0,28473
0 голосов
/ 11 февраля 2019

Вот одно не очень сложное, но рабочее решение:

    #!/usr/bin/env perl 

use strict;
use warnings;
use 5.010;
use Data::Dumper;

#my @first_file_lines = split "\n", `cat ./first_file.txt`;
#my @second_file_lines = split "\n",`cat ./second_file.txt`;
open( my $fh, '<', './first_file.txt' );
open( my $fh1, '<', './second_file.txt' );
chomp ( my @first_file_lines = <$fh> );
chomp (my @second_file_lines = <$fh1>) ;

close( $fh );
close( $fh1 );


my @output = grep { filter( $_, \@second_file_lines ) } @first_file_lines;

sub filter {
    my $current    = shift;
    my $compare_to = shift;

    for my $comp ( @$compare_to ) {
        my $comp1 = $comp;
        $comp1 =~ s/\|/ /;
        if ( $current =~ /^$comp1/ ) {
            say 'equal: ' . "$current   :  $comp";
            return;
        }
    }


    return $current;
}

say Dumper( @first_file_lines );
say Dumper( @second_file_lines );

for my $out ( @output ) {
    `echo "$out" >> ./output.txt`;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...