Извлеките часть строки, используя шаблон, начните со значения переменной в Perl - PullRequest
0 голосов
/ 22 февраля 2011

Я очень новичок в Perl, и я не понимаю, как выполнить эту задачу. У меня есть два файла:

  1. Seq.txt, который содержит много последовательностей (база данных)
  2. PID.txt, который содержит только идентификаторы (запрос) для некоторых последовательностей, которые мне нужно извлечь из файла Seq.txt.

Здесь я даю небольшую часть моих обоих файлов:

Seq.txt содержит:

'>' SCO0700,  probable ABC transporter protein, ATP-binding component. 
MASSMEKPLDHRYRGEHPIRTLVYLFRADRRRLAGAVAVFTVKHSPIWLLPLVTAAIVDT
VVQHGPITDLWTSTGLIMFILVVNYPLHLLYVRLLYGSVRRMGTALRSALCTRMQQLSIG  
'>' SCO0755, putative ABC transporter 797720:799942 forward MW:79858
VSTAQETRGRRRAAPPRRSVPKSRARTVRTPTVLQMEAVECGAASLAMVLGHYGRHVPLE
ELRIACGVSRDGSRASNLLKAARSYGFTAKGMQMDLAALAEVTAPAILFWEFNHYVVYDG  
'>' SCO2305,putative ABC transporter ATP-binding subunit 2474063:2474989 forward MW:32345
MRPTEGTTPAVAFTGAAKAYGDVRAVDGVDLRIGCGETVALLGRNGAGKSTTIALLLGLC
PPDAGTVELFGGPAERAVRAGRVGAMLQEARAVPRVTVGELVAFVAGRYPAPMPVGQALE   
'>' SCO1144, putative ABC transporter ATP-binding protein 1202480:1204282 reverse MW:64637
MHPDRESAWTAPADAVEQPRQVRRILKLFRPYRGRLAVVGLLVGAASLVSVATPFLLKEI
LDVAIPEGRTGLLSLLALGMIFGAVLTSVFGVLQTLISTTVGQRVMHDLRTAVYGRLQQM  
'>' SCO1148, putative ABC transporter 1207772:1209553 forward MW:63721
MIGVAPPSYDPAAPTTANTLPVGARPTVRAYVGELLRRHRRAFLFLVTVNTVAVIASMAG
PYLLGGLVERVSDDARELRLGLTATLFVLALVVQAVFVREVRLRGAVLGERMLADLREDF

PID.txt содержит:

SCO0755  
SCO1144

Код, который я написал:

open (PID, 'PID.txt');  
my @PID = '<'PID'>';  
close(PID);  
open (MSD, 'Seq.txt');  
my @MSD = '<'MSD'>';    
close(MSD);  
chomp(@MSD);  
my $MSD=join (' ', @MSD);  
print "$MSD \n";  
for ($i = 0; $i<=2; $i++) {  
  my $a=$PID[$i];  
  if ($MSD =~ m/$a(.*?)>/)  # ">" end of the string  
  {  
    print "$1 \n";  
    $output= ">".$a.$1;  
    print $output;  
    open (MYFILE, '>>data.txt');  
    print MYFILE "$output\n";    
    close (MYFILE);    
  }  
}

Почему он не распознает $a? Если я поставлю [ $ a ], то оператор связывания распознает $a, но не возвращает желаемую последовательность (с идентификатором, сохраненным в $a), вместо этого он возвращает самую первую последовательность.

Результат, который я ожидаю:

'>' SCO0755, putative ABC transporter 797720:799942 forward MW:79858
VSTAQETRGRRRAAPPRRSVPKSRARTVRTPTVLQMEAVECGAASLAMVLGHYGRHVPLE
ELRIACGVSRDGSRASNLLKAARSYGFTAKGMQMDLAALAEVTAPAILFWEFNHYVVYDG  
'>' SCO1144, putative ABC transporter ATP-binding protein 1202480:1204282 reverse MW:64637
MHPDRESAWTAPADAVEQPRQVRRILKLFRPYRGRLAVVGLLVGAASLVSVATPFLLKEI
LDVAIPEGRTGLLSLLALGMIFGAVLTSVFGVLQTLISTTVGQRVMHDLRTAVYGRLQQM

Ответы [ 3 ]

3 голосов
/ 22 февраля 2011

Во-первых, не используйте $a и $b в своем коде. Это специальные переменные, которые имеют смысл только внутри блока sort; избегайте их в другом месте, вместо этого используйте значимые имена переменных.

Во-вторых,

my @PID = '<'PID'>';

Предполагая, что вы пытаетесь прочитать содержимое PID дескриптора файла в массив, вы имеете в виду:

my @PID = <PID>;

В-третьих, в наши дни наиболее распространенной практикой является использование 3-х аргументных открытых и лексических файловых дескрипторов, например:

open(my $pidfh, '<', 'PID.txt') or die "...";
my @PID = <$pidfh>;
close $pidfh;

У вас есть use strict; в верхней части вашего сценария?

Что бы это ни стоило, я бы прочитал интересующие вас PID-ы в хеш для облегчения поиска, а затем перебрал Seq.txt; помните, какую запись вы просматриваете и сохраняете ее содержимое каждый раз, когда вы видите новую запись, посмотрите, является ли предыдущая, которую вы создали, той, которую вы хотите, и если это так, распечатайте ее. Таким образом, вам не нужно хранить содержимое файла в памяти, что будет полезно, если это очень большой файл.

Примерно так:

#!/usr/bin/perl
use strict;

# Read in a list of PIDs we're interested in
my %want_pid;
open(my $pidfh, '<', 'PID.txt') or die "Failed to open PID.txt - $!";
while (my($pid) = <$pidfh> =~ m{([A-Z0-9]+)}) {
    $want_pid{$pid}++ if $pid;
}

# Now process the file and print entries we want
open(my $seqfh, '<', 'Seq.txt') or die "Failed to open Seq.txt - $!";
my $current_pid;
my $current_text;
while (my $line = <$seqfh>) {
    if (my ($new_pid) = $line =~ m{^ '>' \s+ ([A-Z0-9]+) , }x) {
        # We're at the start of a new entry; if the last one is one we want, 
        # print it.
        if ($want_pid{$current_pid}) {
            print $current_text;
        }

        $current_pid = $new_pid;
        $current_text = $line;
    } else {
        # It's a continuation of an entry
        $current_text .= $line;
    }
}

close $seqfh;

(Возможности для улучшения, но это должно привести вас на правильный путь.)

2 голосов
/ 22 февраля 2011

Я не могу сказать вам, почему вы получаете вывод, который вы получаете, потому что код, который вы разместили, не является допустимым Perl и не будет компилироваться или запускаться - my @PID = '<'PID'>'; синтаксически неверен. (Это должно быть my @PID = <PID>;, без кавычек.) Следовательно, это не тот код, который вы запускаете для получения этих результатов.

Причина, по которой вы не получаете совпадений, заключается в том, что, хотя опубликованный код имеет значение chomp(@MSD), он также не chomp(@PID), поэтому PID будут совпадать только в том случае, если за ними следует новая строка. Что, согласно опубликованным данным, это не так. (И даже если бы они были, chomp(@MSD) удалил бы их.)

Исправление этого сдвигает вас на шаг ближе, но все равно не дает желаемых результатов, потому что ваше регулярное выражение неверно. Попробуйте это вместо этого (с $a переименованным в $target, потому что a: это более значимое имя, а b: $a и $b магические, поэтому вы не должны их использовать): m/'>' $target([^']*)/

Наконец, ваш цикл for ($i...) неправильный, что очень легко сделать с C-style for. Намного лучше использовать for (list).

Исправление всех этих вещей, а также переключение на лексические файловые дескрипторы и форму open с тремя аргументами (как уже упоминалось Дэвидом Precious) и выполнение некоторой общей очистки кода, дает нам:

#!/usr/bin/env perl

use strict;
use warnings;

open my $pid_fh, '<', 'PID.txt';
my @PID = <$pid_fh>;
close $pid_fh;
chomp(@PID);

open my $msd_fh, '<', 'Seq.txt';
my @MSD = <$msd_fh>;
close $msd_fh;
chomp(@MSD);

my $msd = join(' ', @MSD);
my $output;
open my $outfile, '>>', 'data.txt';
for my $target (@PID) {
    if ($msd =~ m/'>' $target([^']*)/) {
        $output = ">" . $target . $1;
        print $output, "\n";
        print $outfile "$output\n";
    }
}

... который производит вывод:

>SCO0755, putative ABC transporter 797720:799942 forward MW:79858 VSTAQETRGRRRAAPPRRSVPKSRARTVRTPTVLQMEAVECGAASLAMVLGHYGRHVPLE ELRIACGVSRDGSRASNLLKAARSYGFTAKGMQMDLAALAEVTAPAILFWEFNHYVVYDG   
>SCO1144, putative ABC transporter ATP-binding protein 1202480:1204282 reverse MW:64637 MHPDRESAWTAPADAVEQPRQVRRILKLFRPYRGRLAVVGLLVGAASLVSVATPFLLKEI LDVAIPEGRTGLLSLLALGMIFGAVLTSVFGVLQTLISTTVGQRVMHDLRTAVYGRLQQM

Правильные последовательности выбраны; Я оставлю их в том формате, в котором вы их просили в качестве упражнения для читателя.

0 голосов
/ 22 февраля 2011

Проверьте, работает ли это для вас:

use warnings;
use strict;

die "Usage: $0 <pid file> <seq file>\n" unless @ARGV == 2;

open my $pid, "<", $ARGV[0] or die "Error: Cannot open file $ARGV[0]: $!\n";
open my $seq, "<", $ARGV[1] or die "Error: Cannot open file $ARGV[1]: $!\n";

my %pid = ();
while ( <$pid> ) {
    chomp;
    s/^\s*(\S*)\s*$/$1/;
    ++$pid{$_};
}


$/ = "\'>\'";
foreach ( <$seq> ) {
    $_ = substr $_, 0, -3;
    my ($p) = split /\,/;
    $p =~ /(\S+)/;
    print "'>'", $_ if exists $pid{$1};
}

С уважением,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...