In Perl, how can I concisely check if a $variable is defined and contains a non zero length string?

前端 未结 9 910
名媛妹妹
名媛妹妹 2020-12-02 07:08

I currently use the following Perl to check if a variable is defined and contains text. I have to check defined first to avoid an \'uninitialized value\' warnin

相关标签:
9条回答
  • 2020-12-02 07:26

    You could say

     $name ne ""
    

    instead of

     length $name > 0
    
    0 讨论(0)
  • 2020-12-02 07:30

    As mobrule indicates, you could use the following instead for a small savings:

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

    You could ditch the defined check and get something even shorter, e.g.:

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

    But in the case where $name is not defined, although the logic flow will work just as intended, if you are using warnings (and you should be), then you'll get the following admonishment:

    Use of uninitialized value in string ne

    So, if there's a chance that $name might not be defined, you really do need to check for definedness first and foremost in order to avoid that warning. As Sinan Ünür points out, you can use Scalar::MoreUtils to get code that does exactly that (checks for definedness, then checks for zero length) out of the box, via the empty() method:

    use Scalar::MoreUtils qw(empty);
    if(not empty($name)) {
        # do something with $name 
    }
    
    0 讨论(0)
  • 2020-12-02 07:33

    The excellent library Type::Tiny provides an framework with which to build type-checking into your Perl code. What I show here is only the thinnest tip of the iceberg and is using Type::Tiny in the most simplistic and manual way.

    Be sure to check out the Type::Tiny::Manual for more information.

    use Types::Common::String qw< NonEmptyStr >;
    
    if ( NonEmptyStr->check($name) ) {
        # Do something here.
    }
    
    NonEmptyStr->($name);  # Throw an exception if validation fails
    
    0 讨论(0)
  • 2020-12-02 07:36

    It isn't always possible to do repetitive things in a simple and elegant way.

    Just do what you always do when you have common code that gets replicated across many projects:

    Search CPAN, someone may have already the code for you. For this issue I found Scalar::MoreUtils.

    If you don't find something you like on CPAN, make a module and put the code in a subroutine:

    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
    

    Then in your code call it:

    use My::String::Util qw( is_nonempty );
    
    if ( is_nonempty $name ) {
        # do something with $name
    }
    

    Or if you object to prototypes and don't object to the extra parens, skip the prototype in the module, and call it like: is_nonempty($name).

    0 讨论(0)
  • 2020-12-02 07:36

    How about

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

    This isn't quite equivalent to your original version, as it will also return false if $name is the numeric value 0 or the string '0', but will behave the same in all other cases.

    In perl 5.10 (or later), the appropriate approach would be to use the defined-or operator instead:

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

    This will decide what to get the length of based on whether $name is defined, rather than whether it's true, so 0/'0' will handle those cases correctly, but it requires a more recent version of perl than many people have available.

    0 讨论(0)
  • 2020-12-02 07:43

    You often see the check for definedness so you don't have to deal with the warning for using an undef value (and in Perl 5.10 it tells you the offending variable):

     Use of uninitialized value $name in ...
    

    So, to get around this warning, people come up with all sorts of code, and that code starts to look like an important part of the solution rather than the bubble gum and duct tape that it is. Sometimes, it's better to show what you are doing by explicitly turning off the warning that you are trying to avoid:

     {
     no warnings 'uninitialized';
    
     if( length $name ) {
          ...
          }
     }
    

    In other cases, use some sort of null value instead of the data. With Perl 5.10's defined-or operator, you can give length an explicit empty string (defined, and give back zero length) instead of the variable that will trigger the warning:

     use 5.010;
    
     if( length( $name // '' ) ) {
          ...
          }
    

    In Perl 5.12, it's a bit easier because length on an undefined value also returns undefined. That might seem like a bit of silliness, but that pleases the mathematician I might have wanted to be. That doesn't issue a warning, which is the reason this question exists.

    use 5.012;
    use warnings;
    
    my $name;
    
    if( length $name ) { # no warning
        ...
        }
    
    0 讨论(0)
提交回复
热议问题