Perl在初始化所有值时使用未初始化值

Perl在初始化所有值时使用未初始化值,perl,Perl,我试图编写一个脚本,计算几个碳氢键的顺序参数,并输出这些值。数学是微不足道的,但当我试图在最后平均值时,我得到了一个“使用未初始化值”错误。 我很清楚这个错误是多么常见和容易修复,但我检查了所有给定的值,所有9212个值都有一个值(我通过打印每个值,将其放入excel文档并搜索空单元格进行检查)。我不知所措,不知道如何进一步调试 我的脚本获取一个输入文件,逐行执行,如果存在某些字符串,则获取x、y、z坐标,对这些坐标进行数学计算(找到两个向量和z轴之间的角度),应将每个$integer部分一起平

我试图编写一个脚本,计算几个碳氢键的顺序参数,并输出这些值。数学是微不足道的,但当我试图在最后平均值时,我得到了一个“使用未初始化值”错误。 我很清楚这个错误是多么常见和容易修复,但我检查了所有给定的值,所有9212个值都有一个值(我通过打印每个值,将其放入excel文档并搜索空单元格进行检查)。我不知所措,不知道如何进一步调试

我的脚本获取一个输入文件,逐行执行,如果存在某些字符串,则获取x、y、z坐标,对这些坐标进行数学计算(找到两个向量和z轴之间的角度),应将每个$integer部分一起平均(因此所有2的平均值等)。它对3个段(2-8、9-10和11-18)执行此操作,将这些段保存到两个数组(@theta_值和@theta2_值),最后将每个“整数”一起平均,以找到向量和z轴之间的平均角度。 总共应该有34个输出值,这确实发生了,但每个值都有一个“使用未初始化值的加法(+)在角度检查程序3.pl第334行,第34303行。”错误,除第一个之外的所有平均值都太小

作为参考,第334行是我的平均值,第34303行是文件的最后一行

一些样本数据是:

ATOM   2199  C22 POPC    1      -9.427  11.863  11.706  1.00  0.00      MEMB
ATOM   2200  H2R POPC    1     -10.347  11.662  12.293  1.00  0.00      MEMB
ATOM   2201  H2S POPC    1      -8.968  10.895  11.443  1.00  0.00      MEMB
ATOM   2211  C23 POPC    1      -9.801  12.641  10.423  1.00  0.00      MEMB
ATOM   2212  H3R POPC    1     -10.136  13.667  10.696  1.00  0.00      MEMB
ATOM   2213  H3S POPC    1     -10.658  12.124   9.934  1.00  0.00      MEMB
ATOM   2214  C24 POPC    1      -8.663  12.751   9.396  1.00  0.00      MEMB
ATOM   2215  H4R POPC    1      -7.763  13.166   9.894  1.00  0.00      MEMB
ATOM   2216  H4S POPC    1      -8.961  13.479   8.607  1.00  0.00      MEMB
*我故意跳过了上面10个无关紧要的原子

按顺序,列表示:物质(不相关)、原子数、原子类型、残基数/分子类型、残基数、x坐标、y坐标、z坐标、α数(不相关)、β列(不相关)和整体分子类型

TLDR; 我的剧本:

#Averaging theta values
for (my $t=2; ($t <= 18); $t++) {
    for (my $j=1; ($j <= $lipid_num); $j++) {
            $sum[$t]= $theta_values[$t][$j] + $sum[$t];
    }
    $average[$t]= $sum[$t] / $lipid_num;
    print "Average theta for carbon $t is $average[$t]\n";
}

#Averaging Theta2 values
for (my $q=2; ($q <= 18); $q++) {
        for (my $b=1; ($b <= $lipid_num); $b++) {
                $sum2[$q]= $theta2_values[$q][$b] + $sum2[$q];
        }
        $average2[$q]= $sum2[$q] / $lipid_num;
        print "Average theta2 for carbon $q is $average2[$q]\n";
}
#平均θ值

对于(my$t=2;($t如果没有输入数据,就不可能在本地重现问题,从而几乎不可能帮助调试。但是,在查看了您的代码之后,我可以提出一些建议,以简化代码,并希望更容易找到问题

首先,几乎所有的循环都在C风格的
for
循环中迭代两个值之间的整数变量。如果您绝对需要的话,这种形式的
for
是存在的,但是perl的for循环形式更具表现力,因此更容易阅读和理解作者的意图

这里只需要一个整数范围;例如

for (my $integer= 2; ($integer <= 8); $integer++) { 
如果您使用整数仅仅是为了索引回数组以获取内容,那么您可以简单地告诉perl您想要迭代数组内容——即,而不是

for (my $line = 0; $line <= $#data; ++$line) {
    if(($data[$line] =~ ... etc ...
    chomp $data[$line];
第二,当你有几个正则表达式在使用时,它有助于将它们的定义和使用分开。它允许读者使用和理解正则表达式本身,而不是(稍后)也就是说,“扩展模式”正则表达式允许ReX定义中的空白。这简直是令人惊讶的是,用空白读取ReGeXes(ReXEXN)有多么容易——因此,我们应该考虑把它简单化为只使用<代码> /x<代码>。
if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {

第三,也许是最不恰当的,因为我认为它可能是一个bug,在你的几个内部循环中

my @splitline = (split /\s+/, $data[$line]);
foreach (@splitline) {
    $x1[0]= $splitline[5];
    $y1[0]= $splitline[6];
    $z1[0]= $splitline[7];
}
再一次-我没有输入数据,因此无法检查-但这几乎肯定是一个错误。您在空白处拆分行-为了讨论,假设它有10个“片段”。然后迭代这些片段(将它们放在默认主题中,
$\ucode>)但是不要参考主题文章本身-也就是说,您没有使用
$\ucode>。因此,代码将第5、6和7部分分别放在x1、y1和z1中10次以上。现在,这可能没什么关系,但正如我所说,这几乎肯定不是您想要的,因此是一个等待发生的错误。您可以(这是简洁性与可读性之间的平衡问题)希望将三个赋值合并为列表形式,并(再次,可选地)消除临时变量,
@splitline

if( $line =~ $has_C2_integer  &&  $line =~ $has_lipid  &&  $line =~ $has_POPC) {
    ( $x1[0], $y1[0], $z1[0] ) = (split /\s+/ $line)[ 5, 6, 7 ];
}
将这些想法结合在一起,可以取代这一点

#Start for lipid count
for (my $lipid=1; ($lipid <= $lipid_num); $lipid++) {
    # First Carbon/Integer counter
    for (my $integer= 2; ($integer <= 8); $integer++) {
        #Split line 1
        for (my $line = 0; $line <= $#data; ++$line) {
                #Search 1.1
                if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                        chomp $data[$line];
                        my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[0]= $splitline[5];
                                $y1[0]= $splitline[6];
                                $z1[0]= $splitline[7];
                        }
                }
                #Search 1.2
                    if(($data[$line] =~ m/\s+H$integer$R\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[1]= $splitline[5];
                                    $y1[1]= $splitline[6];
                                    $z1[1]= $splitline[7];
                        }
                }
                #Search 1.3
                    if(($data[$line] =~ m/\s+H$integer$S\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[2]= $splitline[5];
                                    $y1[2]= $splitline[6];
                                    $z1[2]= $splitline[7];
                        }
                }
        }

…这意味着行数减少了约三分之一,而且(可以说)更具可读性。稍后在程序中,结构几乎一字不差地重复,因此您应该能够再次获得相同的简化。这当然需要严格检查,我不能这样做。最后,仔细看看。只需大约15分钟就可以理解基本内容,并且它将回报您10倍以上(至少).

结果表明,我将没有值的$sum[$t]添加到了有值的内容中,这导致了错误。要解决此问题,我更改为:

$sum[$t]= $theta_values[$t][$j] + $sum[$t];
致:


谢谢大家的帮助。

是否可以将输入数据文件发布到某个地方?如果没有它,问题将无法在本地重现,从而使调试变得困难一个数量级。请尝试先将
@sum
@sum2
数组初始化为全零?此外,您将
$q
从2迭代到18。是否要跳过你的
@sum
@sum2
数组的0和1位置?除非你做些什么,否则这些将不会初始化。你的代码也会从将几乎重复的代码节重构为子例程中受益。另外,
$integer
的任意索引也应该通过一些调整转换为常量对于它们的值。代码注释中的输入格式示例也会为其他试图探索代码的人带来奇迹。第一个观察:这是太多的直截了当的代码。应该将其拆分为子例程。然后您可以实际检查部分过程。此外,它还允许并强制您对代码进行分区和构造你的问题,几乎肯定会导致更好的代码。
my @splitline = (split /\s+/, $data[$line]);
foreach (@splitline) {
    $x1[0]= $splitline[5];
    $y1[0]= $splitline[6];
    $z1[0]= $splitline[7];
}
if( $line =~ $has_C2_integer  &&  $line =~ $has_lipid  &&  $line =~ $has_POPC) {
    ( $x1[0], $y1[0], $z1[0] ) = (split /\s+/ $line)[ 5, 6, 7 ];
}
#Start for lipid count
for (my $lipid=1; ($lipid <= $lipid_num); $lipid++) {
    # First Carbon/Integer counter
    for (my $integer= 2; ($integer <= 8); $integer++) {
        #Split line 1
        for (my $line = 0; $line <= $#data; ++$line) {
                #Search 1.1
                if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                        chomp $data[$line];
                        my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[0]= $splitline[5];
                                $y1[0]= $splitline[6];
                                $z1[0]= $splitline[7];
                        }
                }
                #Search 1.2
                    if(($data[$line] =~ m/\s+H$integer$R\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[1]= $splitline[5];
                                    $y1[1]= $splitline[6];
                                    $z1[1]= $splitline[7];
                        }
                }
                #Search 1.3
                    if(($data[$line] =~ m/\s+H$integer$S\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[2]= $splitline[5];
                                    $y1[2]= $splitline[6];
                                    $z1[2]= $splitline[7];
                        }
                }
        }
my $has_POPC = qr/ \s+ POPC \s+ /x;
#Start for lipid count
for my $lipid (1 .. $lipid_num) {
    my $has_lipid = qr/ \s+ $lipid \s+ /x;

    # First Carbon/Integer counter
    for my $integer (2 .. 8) {
        my $has_C2_integer  = qr/ \s+ C2 $integer   \s+ /x;
        my $has_H_integer_R = qr/ \s+ H  $integer R \s+ /x;
        my $has_H_integer_S = qr/ \s+ H  $integer S \s+ /x;

        #Split line 1
        for my $line (@data) {
            chomp $line;

            #Search 1.1
            if ($line =~ $has_C2_integer && $line =~ $has_lipid && $line =~ $has_POPC)  {
                ($x1[0], $y1[0], $z1[0]) = (split /\s+/ $line)[ 5, 6, 7 ];
            }

            #Search 1.2
            if ($line =~ $has_H_integer_R && $line =~ $has_lipid && $line =~ $has_POPC) {
                ($x1[1], $y1[1], $z1[1]) = (split /\s+/ $line)[ 5, 6, 7 ];
            }

            #Search 1.3
            if ($line =~ $has_H_integer_S && $line =~ $has_lipid && $line =~ $has_POPC) {
                ($x1[2], $y1[2], $z1[2]) = (split /\s+/ $line)[ 5, 6, 7 ];
            }
        }
    }
}
$sum[$t]= $theta_values[$t][$j] + $sum[$t];
$sum[$t]+= $theta_values[$t][$j];