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

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

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

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

Ответ 1

Вы часто видите проверку на определенность, поэтому вам не нужно иметь дело с предупреждением об использовании значения 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 также возвращает undefined. Это может показаться немного глупостью, но это радует математика, которого я, возможно, хотел быть. Это не вызывает предупреждения, поэтому причина этого вопроса существует.

use 5.012;
use warnings;

my $name;

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

Ответ 2

Как показывает функция 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 не может быть определен, вам действительно нужно проверить определенность в первую очередь, чтобы избежать этого предупреждения. Как указывает Sinan Ünür, вы можете использовать Scalar:: MoreUtils, чтобы получить код, который делает именно это (проверяет определенность, затем проверяет нулевую длину) из коробки, с помощью метода empty():

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

Ответ 3

Во-первых, поскольку length всегда возвращает неотрицательное число,

if ( length $name )

и

if ( length $name > 0 )

эквивалентны.

Если вы согласны с заменой значения undefined пустой строкой, вы можете использовать оператор 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 присваивается пустая строка, если она undefined.

Однако, если вы не хотите зависеть от установки 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";

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

Ответ 4

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

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

Ответ 5

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

 $name ne ""

вместо

 length $name > 0

Ответ 6

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

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

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

Или, если вы возражаете против прототипов и не возражаете против дополнительных парсеров, пропустите прототип в модуле и назовите его так: is_nonempty($name).

Ответ 7

my %hash ; 
$hash{"what"} = "What"; 
$hash{"how"} = "How"; 
my $word = $hash{"now"}; 
print $word; 
if (! $word) {
    print "Catch Ya\n"; 
}
else {
    print $word ; 
}

Ответ 8

Как насчет

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

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

В perl 5.10 (или более поздней версии) подходящий подход будет заключаться в том, чтобы использовать вместо него определенный или оператор:

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

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

Ответ 9

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
}