如何在 Perl 中检查多个变量是不是为空

Posted

技术标签:

【中文标题】如何在 Perl 中检查多个变量是不是为空【英文标题】:How to check if several variables are empty in Perl如何在 Perl 中检查多个变量是否为空 【发布时间】:2010-11-10 09:19:31 【问题描述】:

我有一个 Perl 脚本,其中必须先初始化变量,然后脚本才能继续执行。我检查每个变量的冗长if 语句是显而易见的选择。但也许有一种更优雅或更简洁的方法来检查多个变量。

编辑: 我不需要检查“已定义”,它们总是用一个空字符串定义的,我需要检查它们是否都是非空的。

例子:

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

# If-clauses for setting the variables here

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

【问题讨论】:

如果你提供一个你当前如何做的例子,你可能会得到更多/更好的答案,包括如果一个或多个尚未初始化的适当反应。 (抛出错误?将它们设置为默认值?等等) 【参考方案1】:

我假设 empty 表示空字符串,而不仅仅是任何错误值。也就是说,如果 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 );

【讨论】:

+1 用于参数散列,并捕获包括 OP 在内的每个人都将“0”视为未初始化的错误 在您的中间代码 sn-p 中,我没有看到子 validate_nonempty 被使用。它需要在那里吗? @Matt 感谢您注意到这一点。是的,它确实需要在那里......我一定是在摆弄帖子时不小心删除了一些东西。【参考方案2】:
use List::MoreUtils 'all';
say 'Yes' if (all  defined  $var1, $var2, $var3);

【讨论】:

+1 - 我知道有一种 MoreUtils 方法可以做到这一点,但凌晨 4 点懒得找 :) 对于不断地转向模块,尤其是非标准模块,我深感矛盾。一方面,我不希望人们严重地重新发明***,但另一方面,我希望他们能够流利地使用基本的 Perl 功能,这些功能已经存在于核心语言本身的运行方式中。【参考方案3】:

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

对于少量值,直接的 if 检查是恕我直言,最易读/可维护。

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!"; 

如果您必须知道哪些值未定义,您可以使用 for 循环(留作供读者使用的明显练习)或地图技巧:

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; 

【讨论】:

我的观点是,如果你发现自己明确写了$_,你可能在 Perl 中做的事情并不理想。我特别讨厌$_ =~ /foo/。我经常写grep length @listmap hex @listfor (@list) s/foo/bar/。即使keys %h == grep defined $h$_ keys %h 也可以是values %h == grep defined values %h。对于grep,map,first,all,&c,闭包表达式足够短,可以在我的脑海中保存$_ 的“它”含义。对$this$that 进行混合访问的较长代码值得为抽象命名:$_ 并不真正适用。 @tchrist - 好点。鉴于用户澄清他正在检查 "" 而不是 undeflength 是一个不错的选择 - 已编辑。如果不使用$_,您将如何摆脱undefs? @list == grep defined @list 确定它们是否都是,或者@list = grep defined @list 清除那些不是的。【参考方案4】:
use List::Util 'first';

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

【讨论】:

它看起来很奇怪,但它可以工作并且可以让我免于输入“||!”一遍又一遍。 通过 empty,OP 可能意味着 empty string,而不是 false。检查它的标准方法是 Perl 中的length。另外,不要使用$a$b,因为它们是sort 使用的包变量。 @Sinan:OP 用my 声明$a$b。这些不是包变量。谢谢你的好点。 这种方法似乎不是最具可读性/可维护性的(尽管它确实值得我为纯粹的技术优点 +1)。 'all' 或 'any' from List::MoreUtils 更好。【参考方案5】:

您的方式可读且易于理解,这意味着它易于维护。使用de Morgan's laws 重述您的布尔值:

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

这样,您不会在每个变量前添加 not 前缀,并且不会影响可读性。您可以使用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

【讨论】:

以上是关于如何在 Perl 中检查多个变量是不是为空的主要内容,如果未能解决你的问题,请参考以下文章

perl中如何判断一个hash是不是为空

如何检查 Perl 标量变量是不是已初始化?

如何在 tcsh Shell 中检查变量是不是为空?

如何检查 Perl 中的 DBI 查询是不是返回了多个记录?

如何检查三个变量中是不是只有一个不为空?

如何检查变量是不是不为空?