web-dev-qa-db-ja.com

Perlでは、$ variableが定義されており、長さがゼロでない文字列が含まれているかどうかをどのように簡潔に確認できますか?

現在、次のPerlを使用して、変数が定義され、テキストが含まれているかどうかを確認します。 「未初期化値」警告を回避するために、最初にdefinedをチェックする必要があります。

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

これを書くためのより良い(おそらくより簡潔な)方法はありますか?

75
Jessica

定義の確認が頻繁に表示されるため、undef値の使用に関する警告を処理する必要はありません(そしてPerl 5.10では、問題のある変数が通知されます)。

 Use of uninitialized value $name in ...

したがって、この警告を回避するために、人々はあらゆる種類のコードを思いつき、そのコードは、それが存在するバブルガムとダクトテープではなく、ソリューションの重要な部分のように見え始めます。時々、回避しようとしている警告を明示的にオフにして、何をしているのかを示す方が良い場合があります。

 {
 no warnings 'uninitialized';

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

それ以外の場合は、データの代わりに何らかのヌル値を使用します。 Perl 5.10のdefined-or operator を使用すると、警告をトリガーする変数の代わりに、lengthに明示的な空の文字列(定義され、ゼロ長を返す)を指定できます。

 use 5.010;

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

Perl 5.12では、未定義の値の lengthも未定義を返す であるため、少し簡単です。それは少し馬鹿げているように見えるかもしれませんが、それは私が望んでいたかもしれない数学者を喜ばせます。これは警告を発行しません。これがこの質問が存在する理由です。

use 5.012;
use warnings;

my $name;

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

Mobruleが示すように、少し節約する代わりに以下を使用できます。

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

定義されたチェックを捨てて、さらに短くすることができます、例えば:

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

ただし、$nameが定義されていない場合、ロジックフローは意図したとおりに機能しますが、warningsを使用している場合は(そうすべきです)、次の警告が表示されます。

文字列neでの初期化されていない値の使用

したがって、$nameが定義されていない可能性がある場合は、その警告を回避するために、まず定義されているかどうかをまず確認する必要があります。 SinanÜnürが指摘しているように、 Scalar :: MoreUtils を使用して、empty()を介して、そのままで(定義性をチェックしてから、長さゼロをチェックする)コードを取得できます。方法:

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

まず、lengthは常に負でない数を返すため、

if ( length $name )

そして

if ( length $name > 0 )

同等です。

未定義の値を空の文字列で置き換えることに問題がない場合、Perl 5.10の//=演算子を使用して、LHSが定義されていない限り、RHSを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を使用します。

14
Sinan Ünür

変数がundefであるか''であるかを気にしない場合、通常は次のように要約します。

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

シンプルでエレガントな方法で繰り返しを行うことが常に可能であるとは限りません。

多くのプロジェクト間で複製される共通コードがある場合は、常に行うことを行ってください。

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)のように呼び出します。

1
daotoad

あなたは言えた

 $name ne ""

の代わりに

 length $name > 0
1
mob

優れたライブラリ Type :: Tiny は、Perlコードに型チェックを組み込むためのフレームワークを提供します。ここで示しているのは、氷山の最も細い先端であり、最も単純で手動の方法でType :: Tinyを使用しています。

詳細については、 Type :: Tiny :: Manual を確認してください。

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

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

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