2010-11-10 122 views
2

我有一个Perl脚本,其中变量必须在脚本可以继续执行之前被初始化。冗长的if声明,我检查每个变量是明显的选择。但也许有一种更优雅或简洁的方式来检查几个变量。如何在Perl中检查几个变量是否为空

编辑: 我不需要检查“定义”,他们总是定义一个空字符串,我需要检查所有非空。

例子:

my ($a, $b, $c) = ("", "", ""); 

# If-clauses for setting the variables here 

if(!$a || !$b || !$c) { 
    print "Init failed\n"; 
} 
+0

如果您提供了一个当前如何操作的示例,那么您可能会得到更多/更好的答案,包括在一个或多个尚未初始化时的适当反应。 (抛出一个错误?将它们设置为默认值?等等) – 2010-11-10 09:30:10

回答

8

我假设意味着空字符串,不只是任何虚假的价值。也就是说,如果0"0"是永远有效的值初始化后,目前公认的答案会给你错误的结果:

use strict; use warnings; 

my ($x, $y, $z) = ('0') x 3; 
# my ($x, $y, $z) = ('') x 3; 

for my $var ($x, $y, $z) { 
    die "Not properly initialized\n" unless defined($var) and length $var; 
} 

现在,这是一个验证漂亮没用,因为,很可能更多,你如果出现这种情况,想知道哪个变量没有正确初始化。

通过将您的配置参数保存在散列中可以更好地提供服务,以便您轻松检查哪些已正确初始化。

use strict; use warnings; 

my %params = (
    x => 0, 
    y => '', 
    z => undef, 
); 

while (my ($k, $v) = each %params) { 
    validate_nonempty($v) 
     or die "'$k' was not properly initialized\n"; 
} 

sub validate_nonempty { 
    my ($v) = @_; 
    defined($v) and length $v; 
} 

或者,如果要列出所有不正确初始化是:

my @invalid = grep is_not_initialized($params{$_}), keys %params; 
die "Not properly initialized: @invalid\n" if @invalid; 

sub is_not_initialized { 
    my ($v) = @_; 
    not (defined($v) and length $v); 
} 
+0

+1为params散列并捕获包括OP在内的所有人都将“0”视为未初始化的错误 – DVK 2010-11-10 15:56:28

+0

在您的中间代码片段中,我没有看到使用的是“validate_nonempty”子集。它需要在那里吗? – Matt 2016-11-29 15:47:10

+0

@Matt谢谢你的注意。是的,它确实需要在那里......我一定在意外地删除了一些东西的同时摆弄这个帖子。 – 2016-11-29 16:30:28

8

你所说的 “初始化” 是什么意思?具有不是“undef”的值?

对于少量值,直截了当,如果检查是恕我直言,最易读/可维护。

if (!$var1 || !$var2 || !$var3) { 
    print "ERROR: Some are not defined!"; 
} 

顺便说一句,检查!$var是在“0”的可能的错误是在Perl假,因此初始化为“0”将失败该检查的字符串。这是一个很大更好地使用$var eq ""

或者更好的是,空间的东西出来> 3倍的值

if (!$var1   # Use this if your values are guarantee not to be "0" 
    || $var2 eq ""  # This is a LOT better since !$var fails on "0" value 
    || $var3 eq "") { 

    print "ERROR: Some are not defined!"; 
} 

如果有这么多的值,检查上面变得难以阅读(尽管每行检查在第二个例子中,它并没有真正发生过),或者如果值存储在阵列,您可以使用grep抽象掉了检查:

# We use "length" check instead of "$_ eq ''" as per tchrist's comment below 
if (grep { length } ($var1, $var2, $var3, $var4, $var5, @more_args)) { 
    print "ERROR: Some are not defined!"; 
} 

如果你必须知道哪些的价值观a再没有定义,你可以使用循环(留给读者一个明显的锻炼; Tibial),或地图招:

my $i = -1; # we will be pre-incrementing 
if (my @undefined_indexes = map { $i++; $_ ?() : $i } 
           ($var1, $var2, $var3, $var4, $var5, @more_args)) { 

    print "ERROR: Value # $_ not defined!\n" foreach @undefined_indexes; 
} 
+3

我认为,如果您发现自己明确编写'$ _',那么您可能在Perl中做得不是最理想的。我特别讨厌'$ _ =〜/ foo /'。我经常写'grep {length} @ list','map {hex} @ list'或'for(@list){s/foo/bar /}'。即使'键%h == grep {defined $ h {$ _}}键%h'也可以是'values%h == grep {defined} values%h'。闭包表达式足够短,可以在'grep','map','first','all',&c的头部保存'$ _'的含义。对'$ this'和'$ that'进行混合访问的较长代码值得把名称放到抽象中:'$ _'实际上并不适用于此。 – tchrist 2010-11-10 15:26:02

+0

@tchrist - 好点。鉴于用户澄清他正在检查''“'而不是'undef','length'是一个不错的选择 - 编辑。如何在不使用'$ _'的情况下摆脱'undef'? – DVK 2010-11-10 15:49:00

+0

'@list == grep {defined} @ list'来确定它们是否都是,或'@list = grep {defined} @ list'来清除那些不是。 – tchrist 2010-11-10 15:53:11

7
use List::Util 'first'; 

if (defined first { $_ ne "" } $a, $b, $c) { 
    warn "empty"; 
}  
+0

它看起来很奇怪,但它起作用,并且可以省去我输入“||!”的麻烦一遍又一遍地。 – chiborg 2010-11-10 10:09:33

+2

通过* empty *,OP可能意味着*空字符串*,而不是* false *。在Perl中检查长度的标准方法。另外,不要使用'$ a'和'$ b',因为它们是'sort'使用的包变量。 – 2010-11-10 15:16:42

+0

@Sinan:OP使用'my'声明'$ a'和'$ b'。这些不是包变量。谢谢你的好处。 – 2010-11-10 15:37:44

8
use List::MoreUtils 'all'; 
say 'Yes' if (all { defined } $var1, $var2, $var3); 
+0

+1 - 我知道有一个更好的办法做到这一点,但在凌晨4点懒得打扰:) – DVK 2010-11-10 15:36:25

+6

我对于不断转向模块的东西,可能特别是非标准模块深感矛盾。一方面,我不希望人们重蹈覆辙,但另一方面,我希望他们能够熟练掌握基本的Perl功能,这些功能已经存在于核心语言本身的运作方式中。 – tchrist 2010-11-10 15:56:46

3

你的方法是可读的,容易理解的,这意味着它很容易维护。再论用de Morgan's laws您的布尔:

if (not($a and $b and $c)) { 
    warn(qq(Not all variables are initialized!)) 
} 

这样一来,你不是在每一个变量前面的前缀,并且不影响可读性。您可以使用List::UtilList::MoreUtils,但它们不会增加可读性。

正如SinanÜnür所说,如果您将变量放在哈希中,您可以通过哈希解析并列出哪些变量未被初始化。这可能是最好的,如果有很多这些变量,并且列表不断变化。

foreach my $variable qw(a b c d e f g h i j) { 
    if (not $param{$variable}) { 
     warn qq(You didn't define $variable\n); 
    } 
} 

您可以使用Getopts::Long将参数值放入散列而不是单独的变量中。此外,最新版本的Getopts::Long现在可以在任何阵列上运行,而不仅仅是@ARGV