"使用未初始化的值"索引数组时

时间:2014-09-05 21:02:52

标签: arrays perl join

尝试运行下面的代码时,我从Perl收到以下错误

Use of uninitialized value within @words in concatenation (.) or string...

它引用了我尝试创建由三个单词序列组成的数组的行(以$trigrams开头的行)。任何人都可以帮我解决问题吗?

my %hash;
my @words;
my $word;
my @trigrams;
my $i = 0;

while (<>) {

   @words = split;

   foreach $word (@words) {
      $hash{$word}++;

      # Now trying to create the distinct six-grams in the 10-K.
      $trigrams[$i] = join " ", $words[$i], $words[$i + 1], $words[$i + 2];

      print "$words[$i]\n";
      $i++;
   }
}

1 个答案:

答案 0 :(得分:5)

所有发生的事情都是你从阵列@words的末尾掉下来。您正在为@words的每个元素执行循环,因此$i的值从0变为$#words,或者是数组的最终元素的索引。这一行

join " ", $words[$i], $words[$i + 1], $words[$i + 2];

访问数组$words[$i]的最后一个元素以及两个不存在的元素。

在这种情况下,与使用数组当前索引的任何循环一样,最简单的方法是迭代数组 indices 而不是内容。要使join有效,您需要从零开始并在结束前停止两个元素,因此0 .. $#words-2

使用数组 slice 来选择trigram的三个元素也更简洁,并使用将数组插入字符串的事实,如"@array"中所做的那样与join ' ', @array相同。 (更准确地说,它join $", @array$"默认设置为单个空格。)

我建议这个修复。在每个Perl程序的开头,use strictuse warnings必需的,您应该尽可能晚地使用my声明所有变量。

use strict;
use warnings;

my %hash;

while (<>) {

   my @words = split;
   my @trigrams;

   for my $i (0 .. $#words - 2) {
      my $word = $words[$i];
      ++$hash{$word};

      $trigrams[$i] = "@words[$i,$i+1,$i+2]";

      print "$word\n";
   }
}

<强>更新

如果你不是太简洁,你可能会喜欢这个

use strict;
use warnings;

my %hash;

while (<>) {
   my @words = split;
   my @trigrams = map "@words[$_,$_+1,$_+2]", 0 .. $#words-2;
}