Frage Wie kann ich in Perl prägnant überprüfen, ob eine $ Variable definiert ist und eine Zeichenfolge ungleich Null enthält?


Ich benutze derzeit das folgende Perl, um zu überprüfen, ob eine Variable definiert ist und Text enthält. ich muss überprüfen defined zuerst, um eine Warnung "nicht initialisierter Wert" zu vermeiden:

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

Gibt es einen besseren (vermutlich prägnanteren) Weg dies zu schreiben?


70
2017-09-26 00:23


Ursprung


Antworten:


Sie sehen oft die Überprüfung auf Definiertheit, so dass Sie nicht mit der Warnung umgehen müssen, um einen undef-Wert zu verwenden (und in Perl 5.10 sagt es Ihnen die problematische Variable):

 Use of uninitialized value $name in ...

Also, um diese Warnung zu umgehen, kommen die Leute mit allerlei Code auf, und dieser Code fängt an, wie ein wichtiger Teil der Lösung auszusehen und nicht wie der Kaugummi und das Klebeband, das es ist. Manchmal ist es besser zu zeigen, was Sie tun, indem Sie die Warnung, die Sie vermeiden möchten, explizit deaktivieren:

 {
 no warnings 'uninitialized';

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

In anderen Fällen verwenden Sie eine Art Nullwert anstelle der Daten. Mit Perl 5.10 definiert oder Operator, du kannst Geben length eine explizite leere Zeichenkette (definiert und gibt die Nulllänge zurück) anstelle der Variablen, die die Warnung auslöst:

 use 5.010;

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

In Perl 5.12 ist es etwas einfacher, weil length auf einen undefinierten Wert gibt auch undefined zurück. Das mag ein wenig albern erscheinen, aber das freut den Mathematiker, der ich sein wollte. Das gibt keine Warnung aus, weshalb diese Frage existiert.

use 5.012;
use warnings;

my $name;

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

69
2017-09-26 19:27



Wie mobrule angibt, können Sie stattdessen für eine kleine Ersparnis Folgendes verwenden:

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

Sie könnten den definierten Scheck ablegen und etwas noch kürzer bekommen, z.

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

Aber in dem Fall, wo $name ist nicht definiert, obwohl der logische Ablauf wie vorgesehen funktioniert, wenn Sie verwenden warnings (und du solltest sein), dann wirst du folgende Ermahnung bekommen:

Verwendung von nicht initialisierten Werten in String ne

Also, wenn es eine Chance gibt $name möglicherweise nicht definiert, Sie müssen wirklich in erster Linie für die Definiertheit zu überprüfen, um diese Warnung zu vermeiden. Wie Sinan Ünür darauf hinweist, können Sie verwenden Skalar :: MehrUtils um Code zu bekommen, der genau das tut (prüft auf Definiertheit, prüft dann auf Nulllänge) out of the box, über die empty() Methode:

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

21
2017-09-26 00:44



Erstens, seit length gibt immer eine nicht negative Zahl zurück,

if ( length $name )

und

if ( length $name > 0 )

sind gleichwertig.

Wenn Sie einen nicht definierten Wert durch eine leere Zeichenfolge ersetzen möchten, können Sie Perl 5.10 verwenden //= Operator, der die RHS der LHS zuweist, sofern die LHS nicht definiert ist:

#!/usr/bin/perl

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

my $name;

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

Beachten Sie das Fehlen von Warnungen über eine nicht initialisierte Variable als $name wird der leere String zugewiesen, wenn dieser nicht definiert ist.

Wenn Sie jedoch nicht auf die Installation von 5.10 angewiesen sein möchten, verwenden Sie die Funktionen von Skalar :: MehrUtils. Zum Beispiel kann das oben geschrieben werden als:

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

Wenn du nicht klobben willst $name, benutzen default.


14
2017-09-26 10:07



In Fällen, in denen es mir egal ist, ob die Variable ist undef oder gleich '', Ich fasse es normalerweise zusammen als:

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

6
2017-09-28 06:29



Du könntest sagen

 $name ne ""

Anstatt von

 length $name > 0

1
2017-09-26 00:29



Es ist nicht immer möglich, sich wiederholende Dinge auf einfache und elegante Weise zu tun.

Tun Sie einfach, was Sie immer tun, wenn Sie einen gemeinsamen Code haben, der in vielen Projekten repliziert wird:

Suchen Sie CPAN, jemand hat möglicherweise bereits den Code für Sie. Für dieses Problem habe ich gefunden Skalar :: MehrUtils.

Wenn Sie in CPAN etwas nicht finden, das Ihnen gefällt, erstellen Sie ein Modul und fügen Sie den Code in eine Subroutine ein:

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

Dann in Ihrem Code rufen Sie es auf:

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

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

Oder wenn Sie gegen Prototypen protestieren und nicht gegen die zusätzlichen Paren protestieren, überspringen Sie den Prototyp im Modul und nennen Sie es wie folgt: is_nonempty($name).


1
2017-09-26 01:33



Die ausgezeichnete Bibliothek Art :: Winzig bietet ein Framework, mit dem Sie in Ihren Perl-Code Typprüfungen erstellen können. Was ich hier zeige, ist nur die dünnste Spitze des Eisbergs und verwendet Type :: Tiny in der einfachsten und manuellen Art und Weise.

Achten Sie darauf, die Typ :: Tiny :: Handbuch für mehr Informationen.

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

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

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

1
2017-09-26 10:04



Wie wäre es mit

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

Dies entspricht nicht ganz Ihrer ursprünglichen Version, da es auch false zurückgibt $name ist der numerische Wert 0 oder die Zeichenfolge '0', wird sich aber in allen anderen Fällen gleich verhalten.

In Perl 5.10 (oder später) wäre der geeignete Ansatz, stattdessen den definierten oder Operator zu verwenden:

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

Dies entscheidet darüber, wie die Länge basierend auf ob erhalten wird $name ist definiert, als ob es wahr ist, also 0 /'0' wird diese Fälle korrekt behandeln, aber es erfordert eine neuere Version von Perl, als viele Leute zur Verfügung haben.


-2
2017-09-29 13:23



if ($ name)
{
    #since undef und '' beide als falsch auswerten
    #dies sollte nur funktionieren, wenn String definiert und nicht leer ist ...
    #unless Sie erwarten etwas wie $ name = "0" was falsch ist.
    #notice obwohl $ name = "00" nicht falsch ist
}

-3