В Perl, как я могу кратко проверить, определена ли переменная $и содержит строку ненулевой длины?


в настоящее время я использую следующий Perl, чтобы проверить, определена ли переменная и содержит текст. Я должен проверить defined во-первых, чтобы избежать "неинициализированного значения" предупреждение:

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

есть ли лучший (предположительно более краткий) способ написать это?

9 73

9 ответов:

вы часто видите проверку на определенность, поэтому вам не нужно иметь дело с предупреждением об использовании значения undef (и в Perl 5.10 он сообщает вам оскорбительную переменную):

 Use of uninitialized value $name in ...

Итак, чтобы обойти это предупреждение, люди придумывают всевозможные коды, и этот код начинает выглядеть как важная часть решения, а не жевательная резинка и клейкая лента, что это такое. Иногда лучше показать, что вы делаете, явно отключив предупреждение о том, что вы пытаясь избежать:

 {
 no warnings 'uninitialized';

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

в других случаях используйте какое-то нулевое значение вместо данных. С в Perl 5.10 оператор, вы можете дать length явная пустая строка (определенная и возвращающая нулевую длину) вместо переменной, которая вызовет предупреждение:

 use 5.010;

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

в Perl 5.12, это немного проще, потому что length на неопределенное значение также возвращает undefined. Это может показаться немного глупой, но что радует математик я хотел бы быть. Это не выдает предупреждение, поэтому этот вопрос существует.

use 5.012;
use warnings;

my $name;

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

как указывает mobrule, вы можете использовать следующее вместо небольшой экономии:

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 не может быть определено, действительно нужно проверить определенность в первую очередь, чтобы избежать этого предупреждения. Как указывает Синан Унюр, вы можете использовать Скаляр::MoreUtils чтобы получить код, который делает именно это (проверяет определенность, а затем проверяет нулевую длину) из коробки, через empty() способ:

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

во-первых, так как 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 присваивается пустая строка, если это не определено.

однако, если вы не хотите зависеть от установки 5.10, используйте функции, предоставляемые Scalar:: MoreUtils. Например, можно написать так:

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

если вы не хотите колотить $name используйте default.

в тех случаях, когда мне все равно, является ли переменная undef или равно '', Я обычно резюмирую это так:

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

можно сказать

 $name ne ""

вместо

 length $name > 0

не всегда можно делать повторяющиеся вещи простым и элегантным способом.

просто делайте то, что вы всегда делаете, когда у вас есть общий код, который реплицируется во многих проектах:

Поиск 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).

отличная библиотека Тип::Крошечная предоставляет фреймворк, с помощью которого можно построить проверку типов в коде Perl. То, что я показываю здесь, является только самой тонкой вершиной айсберга и использует Type::Tiny самым упрощенным и ручным способом.

будьте уверены, чтобы проверить Тип::Малолетка::Инструкция для получения дополнительной информации.

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

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

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

как о

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

это не совсем эквивалентно вашей первоначальной версии, так как она также вернет false, если $name - это числовое значение 0 или строку '0', но будет вести себя так же во всех остальных случаях.

в perl 5.10 (или более поздней версии) соответствующим подходом было бы использование оператора defined-or вместо этого:

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

это решит, что получить длину на основе ли $name определяется, а не является ли это правдой, поэтому 0/'0' будет обрабатывать эти случаи правильно, но для этого требуется более поздняя версия perl, чем у многих людей.

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
}