Perl:分配3个可能值中的一个变量

时间:2016-08-13 22:45:01

标签: string perl dna-sequence

我有一个DNA序列。我们称之为" ATCG"。我在2个独立的文件中有2个小的DNA序列数据库,我们称之为#34; db1.txt"和" db2.txt"。两个数据库的格式如下:

>name of sequence
EXAMPLESEQUENCEATCGATCG
>name of another sequence
ASECONDEXAMPLESEQUENCEATCGATCG

我想知道我的DNA序列是否包含在其中一个数据库中,如果是的话。那么,我的结果有3个可能的值:我的序列既不在数据库中,也不在db1中,也不在db2中。这是我的代码:

use warnings;
use strict;
my $entry = 'ATCG';
my $returnval = "The sequence is from neither database";

#if in db1
    my $name1;
    my $seq1;
    open (my $database1, "<", "db1.txt") or die "Can't find db1";
    while (<$database1>){
        chomp ($name1 = <$database1>);
        chomp ($seq1 = <$database1>);
        if (
            index($seq1, $entry) != -1
            || index($entry, $seq1) != -1
        ) {
            $returnval = "The sequence is from db1: ". $name1;
            last;
        }
    }

#If in db2:
    my $name2;
    my $seq2;
    open (my $database2, "<", "db2.txt") or die "Can't find db2";
    while (<$database2>){
        chomp ($name2 = <$database2>);
        chomp ($seq2 = <$database2>);
        if(
            index($seq2, $entry) != -1
            || index($entry, $seq2) != -1
        ) {
            $returnval = "The sequence is from db2: ". $name2;
            last;
        }

    }
    print $returnval . "\n";

此代码存在一些问题(可能不止一些)。无论我的序列是什么,$ returnval =&#34;序列来自db2:&#34;最后没有名字。此外,似乎$ name2和$ seq2是未初始化的值,即使代码与db1的代码相同。如果我删除整个部分以测试db2,代码只返回&#34;序列来自db1:&#34;然后是我从数据库复制和粘贴的一些序列的相应名称,而它返回&#34;序列来自两个数据库&#34;对于其他人。

我做错了什么?如何修复未初始化的值,为什么db2的代码不起作用?

编辑: 我忘了提到输出序列在db2中的输出优先于输出它在db1中,如果序列在两者中。

2 个答案:

答案 0 :(得分:2)

主要问题在于while循环的条件,它在每次迭代时读取并丢弃一行,并防止$name$seq变量每次都包含一个名称和序列。删除该条件并将检查文件结束放在循环中应该可以解决问题。它也可以循环遍历两个数据库并对两者应用相同的逻辑,因此您只需要一个循环来检查每个文件的内容。

use warnings;
use strict;
my $entry = 'ATCG';
my $returnval = "The sequence is from neither database";
my @files = qw(db2 db1);

FILE:
for my $file (@files) {
    open my $fh, '<', "$file.txt" or die "Error opening $file: $!";
    while (1) {
        my $name = <$fh>;
        my $seq  = <$fh>;
        if (not defined $seq) {
            warn "Odd number of lines in $file" if defined $name;
            last; # Reached end of file
        }
        chomp($name, $seq);
        if (
            index($seq, $entry) != -1
            or index($entry, $seq) != -1
        ) {
            $returnval = "The sequence is from $file: $name";
            last FILE; # No need to search the others
        }
    }
}

print "$returnval\n";

答案 1 :(得分:0)

我会在子程序中包装比较,特别是因为你必须多次做同样的事情

此解决方案实现子例程matches,该子例程返回文件中匹配序列的名称,如果未找到则返回 false

我已将记录分隔符$/更改为>字符,以便自动分割序列,每个记录由第一个换行符后的名称和其后的序列组成。 tr/\n//d调用将删除序列中的所有换行符(因此它将处理FAST格式支持的多行序列)并对每个序列进行比较

调用代码只使用for循环来调用每个文件名的子例程。一旦找到匹配项,循环就会退出,$name$file设置为匹配的详细信息

根据$name是否为真

来构建和打印消息
use strict;
use warnings 'all';
use feature 'say';

my $entry = 'ATCG';

my ($file, $name);

for $file ( qw/ db2 db1 / ) {
    last if $name = matches($entry, "$file.txt");
}

say $name ?
    "The sequence is from $file: $name" :
    "The sequence is from neither database";


sub matches {
    my ($seq, $file) = @_;

    open my $fh, '<', $file or die qq{Unable to open "$file" for input: $!};

    local $/ = '>';

    while ( <$fh> ) {
        chomp;
        my ($name, $file_seq) = split /\n/, $_, 2;
        $file_seq =~ tr/\n//d;

        return $name if index($file_seq, $seq) >= 0 or index($seq, $file_seq) >= 0;
    }

    return;
}