Perl - ошибка "Использовать неинициализированное значение", когда значение должно быть установлено?

Я сталкиваюсь с ошибкой "Использование неинициализированного значения" при чтении файлов во вложенных циклах 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 неинициализирован. Также интересно то, что для каждой строки входного файла <IN_PVAL>печатает выше "Use of uninitialized value" предупреждение от строки 1 до строки 5772 (см. предупреждение выше), за исключением того, что этот файл содержит только 2886 строк, то есть ровно половину 5772.

Ни один входной файл (<IN_GENE> а также <IN_PVAL>) имеет пустые строки, либо в середине, либо в конце, и оба формата отформатированы, как и ожидалось, с правильным количеством полей, ни одно из которых не является пустым.

Любой совет будет принят во внимание. Спасибо!

3 ответа

Решение

Если $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 для каждой строки в файле гена.

Поскольку мне не о чем продолжать, это в основном образованные догадки. Однако, с некоторой обратной связью, я думаю, что мы можем получить где-нибудь. Я добавил это как ответ, так как чувствовал, что это слишком много информации для комментария.

Анализ

По-видимому, в какой-то момент из разделения не хватает полей, чтобы присвоить значение $gene_chr, Вот почему он становится неинициализированным. Вот эта строка:

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

Это произойдет, если в строке вообще нет вкладок, иначе вы получите пустую строку, и ваша ошибка будет "" не быть числовым в ==, То есть:

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

Так как ваши сообщения об ошибках содержат строки, в два раза превышающие максимальное количество строк во внутреннем файле цикла, я бы предположил, что ваши IN_GENE Файл имеет только две строки данных. Кроме того, я бы предположил, что у него есть завершающая пустая строка, которую вы не заметили, и это является причиной ошибок. Это не полностью складывается, но стоит попробовать, если это решит вашу проблему.

Решение

Попробуйте добавить проверку, чтобы увидеть, есть ли у вас пустые строки. Что-то вроде:

...
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.

"chr" является зарезервированным ключевым словом. Вы не должны использовать это для имени переменной, независимо от того, что это работает.

Вы должны добавить строку print Dumper($gene_chr,$chr,$line_pval); после вашего раскола и use Data::Dumper; на вершине. Он многое расскажет о ваших данных. Я полагаю, проблема может быть в ваших файлах данных.

Может также добавить exit if $. > 10 куда-нибудь выйти после 10 строк, прочитанных из файла, и облегчить отладку.

Другие вопросы по тегам