[perl] Perl에서 $ 변수가 정의되어 있고 길이가 0이 아닌 문자열을 포함하는지 어떻게 간결하게 확인할 수 있습니까?

현재 다음 Perl을 사용하여 변수가 정의되어 있고 텍스트가 포함되어 있는지 확인합니다. defined‘초기화되지 않은 값’경고를 피하기 위해 먼저 확인 해야합니다.

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

이것을 작성하는 더 나은 (아마 더 간결한) 방법이 있습니까?



답변

정의 확인을 자주 볼 수 있으므로 undef 값 사용에 대한 경고를 처리 할 필요가 없습니다 (Perl 5.10에서는 문제가되는 변수를 알려줍니다).

 Use of uninitialized value $name in ...

따라서이 경고를 피하기 위해 사람들은 온갖 종류의 코드를 생각해 내고 그 코드는 풍선 껌과 덕트 테이프가 아닌 솔루션의 중요한 부분처럼 보이기 시작합니다. 때로는 피하려는 경고를 명시 적으로 해제하여 수행중인 작업을 표시하는 것이 더 좋습니다.

 {
 no warnings 'uninitialized';

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

다른 경우에는 데이터 대신 일종의 null 값을 사용하십시오. 함께 펄 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(그리고 그래야만하는 경우) 다음과 같은 경고를 받게됩니다.

문자열 ne에서 초기화되지 않은 값 사용

따라서 $name정의되지 않을 가능성이 있는 경우 해당 경고를 피하기 위해 무엇보다도 먼저 정의를 확인해야합니다. Sinan Ünür가 지적했듯이 Scalar :: MoreUtils 를 사용하면 다음과 같은 empty()방법을 통해 바로 그 작업 (정의성을 확인한 다음 길이가 0인지 확인)을 수행하는 코드를 얻을 수 있습니다 .

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


답변

첫째, length항상 음수가 아닌 숫자를 반환하므로

if ( length $name )

if ( length $name > 0 )

동등합니다.

정의되지 않은 값을 빈 문자열로 대체해도 괜찮다 //=면 LHS가 정의되지 않은 한 RHS를 LHS에 할당하는 Perl 5.10의 연산자를 사용할 수 있습니다 .

#!/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
}

또는 프로토 타입에 반대하고 추가 괄호에 반대하지 않는 경우 모듈에서 프로토 타입을 건너 뛰고 다음과 같이 호출합니다 is_nonempty($name)..


답변

우수한 라이브러리 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