在Perl中,如何简单地检查是否定义了$变量并包含非零长度的字符串?

时间:2009-09-26 00:23:04

标签: perl string

我目前使用以下Perl来检查变量是否已定义并包含文本。我必须首先检查defined以避免'未初始化的值'警告:

if (defined $name && length $name > 0) {
    # do something with $name
}

有没有更好的(可能更简洁)的方式来写这个?

9 个答案:

答案 0 :(得分:70)

您经常会看到对定义性的检查,因此您不必处理使用undef值的警告(在Perl 5.10中它会告诉您有问题的变量):

 Use of uninitialized value $name in ...

因此,为了解决这个警告,人们会提出各种代码,而且代码开始看起来像解决方案的一个重要部分,而不是泡泡糖和胶带。有时,最好通过明确地关闭您要避免的警告来显示您正在做的事情:

 {
 no warnings 'uninitialized';

 if( length $name ) {
      ...
      }
 }

在其他情况下,请使用某种空值而不是数据。使用Perl 5.10's defined-or operator,您可以为length提供一个显式空字符串(已定义,并返回零长度),而不是将触发警告的变量:

 use 5.010;

 if( length( $name // '' ) ) {
      ...
      }

在Perl 5.12中,它更容易因为length on an undefined value also returns undefined。这可能看起来有点愚蠢,但这让我想成为的数学家高兴。这不会发出警告,这就是存在这个问题的原因。

use 5.012;
use warnings;

my $name;

if( length $name ) { # no warning
    ...
    }

答案 1 :(得分:23)

正如专栏所示,您可以使用以下内容代替小额节省:

if (defined $name && $name ne '') {
    # do something with $name
}

你可以放弃定义的支票并获得更短的东西,例如:

if ($name ne '') {
    # do something with $name
}

但是在未定义$name的情况下,虽然逻辑流程将按预期工作,但如果您使用warnings(并且您应该),那么您将获得以下内容警告:

Use of uninitialized value in string ne

因此,如果可能无法定义$name,您确实需要首先检查定义,以避免该警告。正如SinanÜnür指出的那样,您可以使用Scalar::MoreUtils通过empty()方法获得开箱即用的代码(检查定义,然后检查零长度):

use Scalar::MoreUtils qw(empty);
if(not empty($name)) {
    # do something with $name 
}

答案 2 :(得分:14)

首先,由于length始终返回非负数,

if ( length $name )

if ( length $name > 0 )

是等价的。

如果您可以使用空字符串替换未定义的值,则可以使用Perl 5.10的//=运算符将RHS分配给LHS,除非定​​义了LHS:

#!/usr/bin/perl

use feature qw( say );
use strict; use warnings;

my $name;

say 'nonempty' if length($name //= '');
say "'$name'";

请注意,对于未初始化的变量没有警告,如果$name未定义,则为#!/usr/bin/perl use strict; use warnings; use Scalar::MoreUtils qw( define ); my $name; print "nonempty\n" if length($name = define $name); print "'$name'\n"; 分配空字符串。

但是,如果您不想依赖于安装5.10,请使用Scalar::MoreUtils提供的功能。例如,以上内容可以写成:

$name

如果您不想破坏default,请使用{{1}}。

答案 3 :(得分:6)

如果我不关心变量是undef还是等于'',我通常会将其概括为:

$name = "" unless defined $name;
if($name ne '') {
  # do something with $name
}

答案 4 :(得分:1)

你可以说

 $name ne ""

而不是

 length $name > 0

答案 5 :(得分:1)

并不总是能够以简单而优雅的方式做重复的事情。

当您拥有可在多个项目中复制的公共代码时,只需执行您经常执行的操作:

搜索CPAN,有人可能已经为您准备了代码。对于这个问题,我找到了Scalar::MoreUtils

如果您在CPAN上找不到喜欢的内容,请创建一个模块并将代码放在子例程中:

package My::String::Util;
use strict;
use warnings;
our @ISA = qw( Exporter );
our @EXPORT = ();
our @EXPORT_OK = qw( is_nonempty);

use Carp  qw(croak);

sub is_nonempty ($) {
    croak "is_nonempty() requires an argument" 
        unless @_ == 1;

    no warnings 'uninitialized';

    return( defined $_[0] and length $_[0] != 0 );
}

1;

=head1 BOILERPLATE POD

blah blah blah

=head3 is_nonempty

Returns true if the argument is defined and has non-zero length.    

More boilerplate POD.

=cut

然后在你的代码中调用它:

use My::String::Util qw( is_nonempty );

if ( is_nonempty $name ) {
    # do something with $name
}

或者,如果您反对原型并且不反对额外的parens,请跳过模块中的原型,并将其称为:is_nonempty($name)

答案 6 :(得分:1)

优秀的库Type::Tiny提供了一个框架,可用于在Perl代码中构建类型检查。我在这里展示的只是冰山最薄的一角,并且以最简单和手工的方式使用Type :: Tiny。

请务必查看Type::Tiny::Manual以获取更多信息。

use Types::Common::String qw< NonEmptyStr >;

if ( NonEmptyStr->check($name) ) {
    # Do something here.
}

NonEmptyStr->($name);  # Throw an exception if validation fails

答案 7 :(得分:-2)

怎么样

if (length ($name || '')) {
  # do something with $name
}

这与原始版本不完全相同,因为如果$name是数字值0或字符串'0',它也会返回false,但在所有其他情况下表现相同。

在perl 5.10(或更高版本)中,适当的方法是使用defined-or运算符:

use feature ':5.10';
if (length ($name // '')) {
  # do something with $name
}

这将根据是否定义$name来确定获取长度的长度,而不是它是否为真,因此0 / '0'将正确处理这些情况,但它需要更新版本perl比很多人都有。

答案 8 :(得分:-3)

if ($name )
{
    #since undef and '' both evaluate to false 
    #this should work only when string is defined and non-empty...
    #unless you're expecting someting like $name="0" which is false.
    #notice though that $name="00" is not false
}