使用while循环计算碱基的频率,使用Perl计算substr

时间:2014-10-04 08:21:24

标签: perl

我正在尝试用Perl编写来计算DNA序列中每个A / C / G / T碱基的数量。但无法弄清楚我的代码出了什么问题。 " ATCTAGCTAGCTAGCTA"是我给出的那种数据。

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

my $in_file = <$ARGV[0]>;
open( my $FH_IN, "<", $in_file );

my $dna   = <$FH_IN>;
my $index = 0;
my ( $freq_a, $freq_c, $freq_g, $freq_t ) = 0;

my $dna_length = length($dna);
while ( $index < $dna_length ) {
    my $base = substr( $dna, $index, 1 );
    if ( $base eq "A" ) {
        $freq_a++;
        $index++;
        next;
    } elsif ( $base eq "C" ) {
        $freq_c++;
        $index++;
        next;
    } elsif ( $base eq "G" ) {
        $freq_g++;
        $index++;
        next;
    } elsif ( $base eq "T" ) {
        $freq_t++;
        $index++;
        next;
    } else {
        next;
    }
}
print "$freq_a\n$freq_c\n$freq_g\n$freq_t\n";

exit;

我知道有很多方法可以做到,但我想知道的是我做错了所以我可以从错误中吸取教训。

3 个答案:

答案 0 :(得分:2)

Perl有一个特殊的文件句柄可用于解决这些问题:菱形运算符<>。它将从文件名(如果提供)读取输入,如果不提供,则读取标准输入。

其次,既然您只对ACGT感兴趣,也可以使用正则表达式/([ACGT])/g来查找它们。

第三,使用散列是在Perl中计算字符的惯用方法:$count{A}++

所以你的脚本变成了:

use strict;
use warnings;

my %count;
while (<>) {
    while (/([ACGT])/g) {
        $count{$1}++;
    }
}

print "$_\n" for @count{qw(A C G T)};

用法:

script.pl input.txt 

答案 1 :(得分:1)

每次绕过循环时,在$dna_length$index$base打印出来的值会很有帮助 - 在为{{1 }}

如果您将$base的递增移动到循环的结尾($index / if / elsif块之外),您的代码会更强大删除了所有else语句。

另一种“快速修复”是在开始处理之前next输入行。

答案 2 :(得分:1)

好的,到目前为止你做得很好,只有一个问题阻止你的程序工作。

这很明显,但从文件中读取的每一行最后都有一个换行符"\n"。所以发生的事情是$index到达字符串中的换行符,该换行符由else子句处理(因为它不是ACGT)只执行next,因此会反复处理相同的字符。你的程序挂了,对吗?

您可以使用chomp删除换行符,但正确的解决方法是在$index子句中增加else,就像处理所有其他字符一样。所以它看起来像

else {
   ++$index;
   next;
}

正如您所怀疑的,有更好的方法来写这个。您的代码中还有其他一些恶意内容,但这种更改应该会让您暂时停止。