簡體   English   中英

使用模式提取字符串的一部分,以Perl中的variable值開頭

[英]Extract a part of string using a pattern, start with a value of variable in Perl

我是Perl的新手,我對如何執行此任務感到困惑。 我有兩個文件:

  1. Seq.txt,其中包含許多序列(數據庫)
  2. PID.txt,其中僅包含我需要從Seq.txt文件中提取的某些序列的ID(查詢)。

在這里,我給出了兩個文件的一小部分:

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但不返回我想要的序列(ID存儲在$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

首先,不要在代碼中使用$a$b 它們是特殊的變量,僅在sort塊內有意義。 避免在其他地方使用它們,請改用有意義的變量名。

其次,

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

假設您試圖將文件句柄PID的內容讀入數組,則表示:

my @PID = <PID>;

第三,當今常見的最佳實踐是使用3-arg開放式和詞法文件句柄,例如:

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;

(有待改進的空間,但這應該可以使您走上正確的軌道。)

我不能告訴你為什么要得到輸出,因為發布的代碼不是有效的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樣式的for容易犯的錯誤。 更好地for (list)

修復所有這些問題,以及切換到詞法文件句柄和open的三參數形式(如David 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

選擇正確的順序; 我將保留它們的格式完全與您要求的一樣,以供讀者練習。

測試這是否適合您:

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};
}

問候,

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM