【问题标题】:Perl - "Use of uninitialized value" error when value should be set?Perl - 应该设置值时出现“使用未初始化的值”错误?
【发布时间】:2015-03-12 14:17:58
【问题描述】:

在嵌套的“while”循环中读取文件时遇到“使用未初始化的值”错误。我已将代码缩减到最低限度,并删除了文件名/目录以保护隐私:

#/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;

my $line_gene = undef;
my $gene_name = undef;
my $gene_chr  = undef;
my $gene_pos  = undef;
my $line_pval = undef;
my $chr       = undef;
my $pos_start = undef;
my $pos_end   = undef;
my $pos_mid   = undef;
my $pval      = undef;

open(IN_GENE,"somefile_gene") || die "Failed, gene\n";
open(IN_PVAL,"somefile_pval") || die "Failed, pval\n";

while ($line_gene = <IN_GENE>) {
   chomp $line_gene;
   ($gene_name,$gene_chr,$gene_pos) = split(/\t/,$line_gene);
   while ($line_pval = <IN_PVAL>) {
      chomp $line_pval;
      ($chr,$pos_start,$pos_end,undef,undef,$pval) = split(/\t/,$line_pval);
      $pos_mid = ($pos_start + $pos_end)/2;
      if ($gene_chr == $chr) {
         print $gene_chr."\t".$chr."\n";
      }

   }
   seek IN_PVAL, 0, 0;
}
exit;

当我运行此代码时,我收到以下错误消息:

Use of uninitialized value $gene_chr in numeric eq (==) at Xtest.pl line 36,
<IN_PVAL> line 5772 (#1)

然后遵循这些"Use of uninitialized value" 警告是打印到标准输入的正确行:

6       6
1       1
20      20
...     ...

除非我明显做错了什么,否则我看不出它为什么认为$gene_chr 未初始化。有趣的是,对于输入文件&lt;IN_PVAL&gt; 的每一行,它都会从第 1 行到第 5772 行打印上述"Use of uninitialized value" 警告(见上面的警告),除了这个文件只有 2886 行,正好是 5772 的一半。

两个输入文件(&lt;IN_GENE&gt;&lt;IN_PVAL&gt;)都没有空行,无论是在中间还是在末尾,并且都按照预期的格式使用正确数量的字段,其中没有一个是空的。

任何建议将不胜感激。谢谢!

【问题讨论】:

  • 显示产生错误的两个文件的摘录。
  • @JESUISCHARLIE 在您建议查看文件(连同 Sebastian)后,我发现 &lt;IN_PVAL&gt; 的 2886 行中有 3 行有多个空格分隔字段而不是制表符 - 替换这些似乎已经修复了问题!谢谢你:)

标签: perl file while-loop initialization


【解决方案1】:

如果$gene_chr 未定义,则这意味着,对于somefile_gene 的一行或多行,

($gene_name,$gene_chr,$gene_pos) = split(/\t/,$line_gene);

返回 undef 作为它的第二个值(或返回少于两个值,这实际上是一回事)。

我可以想到两种可能发生这种情况的方式:

1) 行不包含制表符,导致将整个未拆分行放入$gene_name。这可能是由于错误地使用空格而不是制表符来分隔字段的行。

2) 在第一个值之后,行包含两个连续的制表符。如果$gene_name 的长度变化很大,这可能是由于有人试图让字段排列得更“漂亮”以进行视觉呈现。

另外有趣的是对于输入文件的每一行 ,它会打印上面的“使用未初始化的值”警告 从第 1 行到第 5772 行(见上面的警告),除了这个文件 只有 2886 行,正好是 5772 的一半。

它显示的行号只是从文件中读取了多少行的计数器。由于您 seek 在每次传递时都回到文件的开头而不是关闭并重新打开它,因此计数器永远不会重置。

从 1 到(2 * pval 文件中的行数)的行号表明您在 pval 文件中的错误位于前两行,分别为 1..2886 和 2887..5772,分别。如果错误出现在文件的后面,则计数器会更高。

此外,作为一般提示,除非 pval 文件中的行非常长,否则我会认真考虑是否可以将其内容读入以$pval_chr 为键的散列中,然后替换整个内循环与

if (exists $pval_hash{$gene_chr}) { ... do stuff ... }

如果基因文件中的行数多于几行,这将显着提高性能,因为它不需要为基因文件中的每一行重新读取 pval 文件。

【讨论】:

  • 我不会说它会“显着”提高性能。 Perl 非常擅长阅读文本文件。它可能会提高性能,但除非文件很大,否则不会有很大的不同。 22.
  • 谢谢戴夫 - 你是对的。该文件的前两行确实有多个空格而不是制表符,这解释了为什么我没有在视觉上选择它们。我想使用“cut”快速检查会发现这个 - 哦!由于我对 perl 还很陌生,所以我不知道当您使用 seek 时行数不会重置(尽管它完全有道理)!替代散列版本会很有用,但由于我简化了代码,在这种情况下不可能使用散列,因为$gene_chr == $chr&lt;IN_PVAL&gt; 文件中不是唯一的!不过感谢您的帮助!
【解决方案2】:

“chr”是保留关键字。无论如何,您都不应该将其用作变量名。

您应该在拆分后添加一行print Dumper($gene_chr,$chr,$line_pval);,并在顶部添加一行use Data::Dumper;。它会告诉你很多关于你的数据的信息。我想问题可能出在您的数据文件中。

也许还可以在某处添加 exit if $. &gt; 10 以在从文件中读取 10 行后退出,并使调试更容易。

【讨论】:

  • 这应该是一条评论。
  • 感谢 Sebastian - 我之前看过 Data::Dumper,但在尝试了您的建议之后,我对它为什么有用以及如何使用它有了更好的了解。我不知道$chr 是保留的-我会调查的。我会赞成你的回答,因为它很有用,但我还没有足够的声誉!无论如何,感谢您的宝贵时间!
【解决方案3】:

由于我没有太多事情要做,这主要是有根据的猜测。但是,有了一些反馈,我认为我们可以有所收获。我添加了这个作为答案,因为我觉得评论信息太多了。

分析

显然在某些时候,拆分中没有足够的字段来为$gene_chr 分配值。这就是它变得未初始化的原因。就是这一行:

($gene_name,$gene_chr,$gene_pos) = split(/\t/,$line_gene);

如果该行中根本没有制表符,则会发生这种情况,否则您将得到一个空字符串,并且您的错误将是关于""== 中不是数字。即:

Argument "" isn't numeric in numeric eq (==)

由于您的错误报告的行数是内部循环文件中最大行数的两倍,因此我推测您的 IN_GENE 文件只有两行数据。此外,我猜它有一个尾随 blank 行,你没有注意到,这就是导致错误的原因。它并没有完全加起来,但值得一试,看看它是否能解决您的问题。

解决方案

尝试添加检查以查看是否有空行。比如:

...
while ($line_gene = <IN_GENE>) {
   chomp $line_gene;
   unless ($line_gene =~ /\S/) {   # unless the line contains non-whitespace
       warn "Warning: Blank line in gene file";
       next;
   }

这将警告您有空行,并跳过它们。警告(以及其他错误)转到 STDERR,这意味着您可以将它们与 STDOUT 中的标准输出分开。

【讨论】:

  • 感谢 TLP - 你是对的,我发现了问题 - 三行(两行在开头,一行在结尾)有多个空格而不是制表符,因此这些行未定义 $gene_chr!这也解释了为什么我没有通过目视检查找到它们,因为它们看起来仍然像制表符一样!我会赞成你的回答,但我没有足够的代表。还是一样的谢谢你:)
猜你喜欢
  • 2014-02-05
  • 1970-01-01
  • 2015-08-03
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
相关资源
最近更新 更多