如何使用Perl正则表达式去除'if'结构中未初始化的值的使用

时间:2012-05-26 00:35:00

标签: perl

如何使用Perl正则表达式摆脱在if构造中使用未初始化的值?

使用下面的代码时,我会使用未初始化的值消息。

     if($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/)

使用下面的代码时,我没有输出。

     if(defined($arrayOld[$i]) =~ /-(.*)/ || defined($arrayOld[$i]) =~ /\#(.*)/)

检查变量是否具有给定上述代码的值的正确方法是什么?

3 个答案:

答案 0 :(得分:2)

尝试:

if($arrayOld[$i] && $arrayOld[$i] =~ /-|\#(.*)/)

在对它运行regx之前,首先检查$ arrayOld [$ i]的值。 (还将||合并到正则表达式中。)

答案 1 :(得分:1)

根据评论中的错误消息,您正在访问未定义的@arrayOld元素。在没有看到其余代码的情况下,这可能表明程序中存在错误,或者只是预期的行为。

如果你理解为什么 $arrayOld[$i]undef,并且你想在没有收到警告的情况下允许这样做,那么你可以做几件事。 Perl 5.10.0引入了defined-or operator //,您可以用它来替换{​​{1}}的空字符串:

undef

或者,您可以关闭警告:

use 5.010;
...
if(($arrayOld[$i] // '') =~ /-(.*)/ || ($arrayOld[$i] // '') =~ /\#(.*)/)

在这里,我使用do来限制警告被禁用的时间。但是,如果if (do { no warnings 'uninitalized'; $arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/ }) $i,则关闭警告也会抑制警告。使用undef可以准确指定允许的//内容,以及应该使用的确切值,而不是undef

注意:undef正在defined函数的结果上运行模式匹配,这将是一个真/假值;不是你要测试的字符串。

答案 2 :(得分:1)

要以狭隘的方式回答您的问题,您可以使用

阻止该行代码中的未定义值警告
if (defined $i && defined $arrayOld[$i]
      && ($arrayOld[$i] =~ /-(.*)/ || $arrayOld[$i] =~ /\#(.*)/))
{
  ...;
}

也就是说,评估$i或表达式$arrayOld[$i]可能会导致未定义的值。请注意上面写的必要括号,因为&&||之间的优先级不同,前者绑定更紧密。对于问题中的特定模式,您可以通过将模式组合到一个正则表达式来回避这个优先级问题,但在一般情况下这可能很棘手。

我建议不要使用上面令人不快的代码。继续阅读,看看你的问题的优雅解决方案,Perl为你工作,更容易阅读。

回顾

your earlier question稍微宽泛的上下文中,$i是一个循环变量,并且肯定会定义构造,因此测试$i是过度的。你的代码盲目地从@arrayOld中提取元素,并且Perl很乐意。如果没有任何内容,则会得到未定义的值。

这种一对一的偷窥和戳戳在C程序中很常见,但在Perl中,几乎总是一个红旗,你可以更优雅地表达你的算法。考虑下面的完整的工作示例。

工作演示

#! /usr/bin/env perl

use strict;
use warnings;
use 5.10.0;  # given/when

*FILEREAD = *DATA;  # for demo only

my @interesting_line = (qr/-(.*)/, qr/\#(.*)/);

$/ = ""; # paragraph mode
while(<FILEREAD>) {
  chomp;
  my @arrayOld = split /\n/;
  my @arrayNewLines;

  for (1 .. @arrayOld) {
    given (shift @arrayOld) {
      push @arrayNewLines, $_ when @interesting_line;
      push @arrayOld, $_;
    }
  }

  print "\@arrayOld:\n",      map("$_\n", @arrayOld), "\n",
        "\@arrayNewLines:\n", map("$_\n", @arrayNewLines);
}

__DATA__
#SCSI_test         # put this line into  @arrayNewLines      
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd
- ccccccccccccccc  # put this line into @arrayNewLines

前面的事情

该行

use 5.10.0;

启用Perl的given/when switch statement,这可以很好地决定哪个数组获得给定的输入行。

如评论所示

*FILEREAD = *DATA;  # for demo only

用于此Stack Overflow演示。在您的真实代码中,您有open FILEREAD, ...。将问题中的输入放入Perl的DATA文件句柄中,可以在一个独立的单元中显示代码和输入,然后我们将FILEREAD别名为DATA,以便其余代码落入你没有大惊小怪。

主要事件

处理的核心是

for (1 .. @arrayOld) {
  given (shift @arrayOld) {
    push @arrayNewLines, $_ when @interesting_line;
    push @arrayOld, $_;
  }
}

请注意,没有defined个检查甚至是明确的正则表达式匹配!没有$i$arrayOld[$i]!发生了什么事?

首先是@arrayOld,其中包含当前段落中的所有行,并且希望以@arrayNewLines中的有趣行和其他所有行@arrayOld结束。上面的代码使用shift@arrayOld开出下一行。如果该行很有趣,我们会push@arrayNewLines的末尾。否则,我们会将其放回@arrayOld

的末尾

语句修饰符when @interesting_line与来自given的主题执行隐式智能匹配。正如“Smart matching in detail,”中针对数组进行智能匹配时所解释的那样,Perl隐式地遍历它并在第一次匹配时停止。在这种情况下,数组@interesting_line包含与要移动到@arrayNewLines的行匹配的已编译正则表达式。如果当前行($_感谢given)与这些模式中的任何一个都不匹配,则会返回@arrayOld

我们完成上述过程scalar @arrayOld次,即对当前段落中的每一行执行一次。这样,我们只处理一次所有内容,而不必担心当前数组索引所在的繁琐记账。无论@arrayOld之后剩下的是什么,shift s必须是我们push回到它上面的行,这是输入中发生的顺序中不感兴趣的行。

样本输出

对于问题中的输入,输出为

@arrayOld:
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd

@arrayNewLines:
#SCSI_test         # put this line into  @arrayNewLines      
- ccccccccccccccc  # put this line into @arrayNewLines