perl:截断使用未初始化的值和输出

时间:2012-09-13 16:03:52

标签: perl

我正在尝试使用以下脚本来重排文件中序列(行)的顺序。我不确定如何“初始化”值 - 请帮助!

print "Please enter filename (without extension): ";
my $input = <>;
chomp $input;

use strict;
use warnings;

print "Please enter total no. of sequence in fasta file: ";
my $orig_size = <>*2-1;
chomp $orig_size;

open INFILE, "$input.fasta"
   or die "Error opening input file for shuffling!";
open SHUFFLED, ">"."$input"."_shuffled.fasta"
   or die "Error creating shuffled output file!";

my @array  = (0); # Need to initialise 1st element in array1&2 for the shift function
my @array2 = (0);
my $i      = 1;
my $index  = 0;
my $index2 = 0;

while (my @line = <INFILE>){

    while ($i <= $orig_size) { 

        $array[$i] = $line[$index];
        $array[$i] =~ s/(.)\s/$1/seg;

        $index++;
        $array2[$i] = $line[$index];
        $array2[$i] =~ s/(.)\s/$1/seg;

        $i++;
        $index++;
    }
}

my $array  = shift (@array); 
my $array2 = shift (@array2);

for ($i = my $header_size; $i >= 0; $i--) { 

    my $j = int rand ($i+1);
    next if $i == $j;
    @array[$i,$j]  = @array[$j,$i];
    @array2[$i,$j] = @array2[$j,$i];
}

while ($index2 <= my $header_size) { 

    print SHUFFLED "$array[$index2]\n";
    print SHUFFLED "$array2[$index2]\n";
    $index2++;
}
close INFILE;
close SHUFFLED;

我收到了这些警告:

Use of uninitialized value in substitution (s///) at fasta_corrector6.pl line 27, <INFILE> line 578914.
Use of uninitialized value in substitution (s///) at fasta_corrector6.pl line 31, <INFILE> line 578914.
Use of uninitialized value in numeric ge (>=) at fasta_corrector6.pl line 40, <INFILE> line 578914.
Use of uninitialized value in addition (+) at fasta_corrector6.pl line 41, <INFILE> line 578914.
Use of uninitialized value in numeric eq (==) at fasta_corrector6.pl line 42, <INFILE> line 578914.
Use of uninitialized value in numeric le (<=) at fasta_corrector6.pl line 47, <INFILE> line 578914.
Use of uninitialized value in numeric le (<=) at fasta_corrector6.pl line 50, <INFILE> line 578914.

3 个答案:

答案 0 :(得分:3)

首先,您在以下位置阅读整个输入文件:

  use IO::File;
  my @lines = IO::File->new($file_name)->getlines;
然后你将它洗牌:

  use List::Util 'shuffle';
  my @shuffled_lines = shuffle(@lines);

然后你把它们写出来:

  IO::File->new($new_file_name, "w")->print(@shuffled_lines);

有关how to shuffle an array的Perl常见问题解答中有一个条目。另一个条目tells of the many ways to read a file in one go。 Perl常见问题包含大量关于如何做许多常见事情的样本和琐事 - 这是继续学习更多关于Perl的好地方。

答案 1 :(得分:2)

我无法确定究竟出了什么问题,但您的代码有些奇怪:

钻石运营商

Perl的Diamond运算符<FILEHANDLE>从文件句柄中读取一行。如果未提供文件句柄,则将每个命令行Argument(@ARGV)视为文件并读取。如果没有参数,则使用STDIN。更好地自己指定。你还应该chomp 之前使用该行进行arithemtics,而不是之后。请注意,不以数字开头的字符串将被视为数字0。你应该检查数字(使用正则表达式?)并包括错误处理。

Diamond / Readline运算符对上下文敏感。如果在标量上下文中给出(例如,条件,标量赋值),则返回一行。如果在列表上下文中给出,例如作为函数参数或数组赋值,它将所有行作为数组返回。所以

while (my @line = <INFILE>) { ...

不会给你一行但是所有行都相当于

my @line;
if (@line = <INFILE>) { ...

阵列体操

在阅读完行后,您尝试进行一些手动咀嚼。在这里,我在@line中删除所有尾随的空格,在一行中:

s/\s+$// foreach @line;

在这里,我删除了所有非领先的空格(你的正则表达式实际上是在做什么):

s/(?<!^)\s//g foreach @line;

要将一个元素交替填充到两个数组中,这可能也有效:

for my $i (0 .. $#@line) {
   if ($i % 2) {
     push @array1, shift @line;
   } else {
     push @array2, shift @line;
   }
}

my $i = 0;
while (@line) {
   push ($i++ % 2 ? @array1 : @array2), shift @line
}

数组索引的手动记录很麻烦且容易出错。

你的for-loop可以写成mor idiomatic

for my $i (reverse 0 .. $header_size)

请注意,如果之前没有声明,则可以在循环初始化中声明$header_size,但它会产生undef值,因此您将undef分配给$i导致一些错误消息,因为undef不应该用于arithemtic操作。作业总是将右侧分配给左侧。

答案 2 :(得分:2)

关于您之前的问题,我提供了this answer,并注意到您的代码失败了,因为您尚未初始化循环条件中使用的名为$header_size的变量。你不仅重复了这个错误,你已经通过每次尝试访问它时开始用my声明变量来详细阐述它。

for ($i = my $header_size; $i >= 0; $i--) { 
#         ^^--- wrong!

while ($index2 <= my $header_size) { 
#                 ^^--- wrong!

默认情况下,使用my声明的变量为空(undef)。 $index2此处除了undef之外永远不会包含任何内容,并且您的循环只会运行一次,因为0 <= undef将评估为true(尽管有未初始化的警告)。

请接受我的建议并为$header_size设置一个值。并且在声明变量时仅使用my,而不是每次使用它时都使用use strict; use warnings; use Tie::File; use List::Util qw(shuffle); tie my @file, 'Tie::File', $filename or die $!; for my $lineno (shuffle 0 .. $#file) { print $line[$lineno]; } untie @file; # all done

更好的解决方案

看到上面的错误,您的输入文件似乎相当大。如果文件中有超过500,000行,则表示您的脚本将消耗大量内存来运行。使用Tie::File之类的模块并仅使用数组索引可能是值得的。例如:

{{1}}