web-dev-qa-db-fra.com

En Perl, comment puis-je vérifier de manière précise si une variable $ est définie et contient une chaîne de longueur non nulle?

J'utilise actuellement le Perl suivant pour vérifier si une variable est définie et contient du texte. Je dois d'abord vérifier defined pour éviter un avertissement 'valeur non initialisée':

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

Existe-t-il une meilleure façon (probablement plus concise) d’écrire cela?

75
Jessica

Vous voyez souvent le contrôle de définition afin de ne pas avoir à gérer l'avertissement d'utilisation d'une valeur undef (et dans Perl 5.10, il indique la variable incriminée):

 Use of uninitialized value $name in ...

Donc, pour contourner cet avertissement, les gens élaborent toutes sortes de codes, et ce code commence à ressembler à une partie importante de la solution plutôt qu’à la gomme à mâcher et au ruban adhésif. Parfois, il est préférable de montrer ce que vous faites en désactivant explicitement l'avertissement que vous essayez d'éviter:

 {
 no warnings 'uninitialized';

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

Dans d'autres cas, utilisez une sorte de valeur null au lieu des données. Avec opérateur défini par-ou de Perl 5.1 , vous pouvez donner à length une chaîne vide explicite (définie, et redonner une longueur égale à zéro) à la place de la variable qui déclenchera l'avertissement:

 use 5.010;

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

En Perl 5.12, c'est un peu plus facile car length sur une valeur indéfinie renvoie également indéfini . Cela peut sembler un peu idiot, mais cela plaira au mathématicien que j’aurais peut-être voulu être. Cela n'émet aucun avertissement, c'est la raison pour laquelle cette question existe.

use 5.012;
use warnings;

my $name;

if( length $name ) { # no warning
    ...
    }
72
brian d foy

Comme l'indique mobrule, vous pouvez utiliser les éléments suivants pour réaliser de petites économies:

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

Vous pouvez abandonner le contrôle défini et obtenir quelque chose d'encore plus court, par exemple:

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

Mais dans le cas où $name n'est pas défini, bien que le flux logique fonctionne exactement comme prévu. Si vous utilisez warnings (et vous devriez le faire), vous obtiendrez alors l'avertissement suivant:

Utilisation de la valeur non initialisée dans la chaîne ne

Donc, s'il y a une chance que $name _ n'est peut-être pas défini, vous devez vraiment vérifier sa définition avant tout pour éviter cet avertissement. Comme le fait remarquer Sinan Ünür, vous pouvez utiliser Scalar :: MoreUtils pour obtenir le code qui fait exactement cela (vérifie la définition, puis vérifie la longueur nulle) par le biais de la touche empty() méthode:

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

Premièrement, puisque length renvoie toujours un nombre non négatif,

if ( length $name )

et

if ( length $name > 0 )

sont équivalents.

Si vous êtes prêt à remplacer une valeur non définie par une chaîne vide, vous pouvez utiliser l'opérateur //= De Perl 5.10, qui attribue le RHS au LHS sauf si le LHS est défini:

#!/usr/bin/Perl

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

my $name;

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

Notez que l'absence d'avertissements concernant une variable non initialisée, car $name Se voit attribuer la chaîne vide si elle n'est pas définie.

Toutefois, si vous ne voulez pas dépendre de l'installation de la version 5.10, utilisez les fonctions fournies par Scalar :: MoreUtils . Par exemple, ce qui précède peut s’écrire comme suit:

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

Si vous ne voulez pas écraser $name, Utilisez default.

14
Sinan Ünür

Dans les cas où je ne me soucie pas de savoir si la variable est undef ou égale à '', Je le résume habituellement comme suit:

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

Il n'est pas toujours possible de faire des choses répétitives de manière simple et élégante.

Faites ce que vous faites toujours lorsque vous avez un code commun qui est répliqué sur de nombreux projets:

Recherchez sur CPAN, quelqu'un a peut-être déjà le code pour vous. Pour ce problème, j'ai trouvé Scalar :: MoreUtils .

Si vous ne trouvez pas quelque chose que vous aimez sur CPAN, créez un module et insérez le code dans un sous-programme:

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

Ensuite, dans votre code, appelez-le:

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

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

Ou si vous vous opposez à des prototypes et non à des parenthèses supplémentaires, ignorez le prototype dans le module et appelez-le comme suit: is_nonempty($name).

1
daotoad

Tu pourrais dire

 $name ne ""

au lieu de

 length $name > 0
1
mob

L'excellente bibliothèque Type :: Tiny fournit un cadre permettant de générer la vérification de type dans votre code Perl. Ce que je montre ici n’est que la partie la plus fine de l’iceberg et utilise Type :: Tiny de la manière la plus simple et la plus manuelle.

Veillez à consulter le Type :: Tiny :: Manual pour plus d'informations.

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

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

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