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


83

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

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

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

답변:


80

정의 확인을 자주 볼 수 있으므로 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
    ...
    }

4
또한, v5.12 이상에서, length undefundef를 대신 경고 및 부울 맥락에서 0을 반환 반환, 미확정 당신이 v5.12을 대상으로 이상하고 만약 그렇다면, 당신은 그냥 쓸 수 있습니다, 단지 0 거짓과 같습니다if (length $name) { ... }
rjbs

24

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 
}

17

첫째, 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.


"// ="멘션에 대한 +1 (시난의 대답이 될지 어떻게 알 수 있었습니까? :)
DVK

4
이 경우에는 데이터가 부작용으로 변경되므로 // =를 사용하지 않습니다. 대신 약간 더 짧은 length( $name // '' ).
brian d foy

@brian d' foy 기능에서 수행되는 작업에 따라 달라집니다.
Sinan Ünür

+1 ////=연산자는 현존하는 가장 유용한 특수 연산자 일 수 있습니다.
Chris Lutz

1
@rjbs가 v5.12으로, 내 대답에 지적으로 나중에 length지금은 숫자가 아닌 것을 반환 할 수 있습니다 (하지만 NaN이를)
브라이언 D를 포이

5

변수가 undef같거나 같은지 상관하지 않는 경우 ''일반적으로 다음과 같이 요약합니다.

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

Perl 5.10에서 이것은 $name //= "";Sinan이 게시 한 그대로 단축 할 수 있습니다 .
Chris Lutz

Perl 5.10이 없더라도 다음과 같이 쓸 수 있습니다$name ||= "";
RET

1
@RET : 넌 사용할 수 없어 || 연산자는 문자열 '0'을 ''로 대체하기 때문입니다. 그것이 사실이 아니라 정의되어 있는지 확인해야합니다.
brian d foy

Chris, RET : 그래, 알아. 내가 특별히 제시카가 사이의 차이와 관련되지 않은 경우 제안려고 undef하고 "", 그녀가 다른 하나를 변경하고 하나의 테스트를 사용해야합니다. 이것은 게시 된 다른 솔루션이 훨씬 더 나은 일반적인 경우에는 작동하지 않지만이 특정 경우에는 깔끔한 코드로 이어집니다. 더 명확하게하기 위해 내 대답을 바꿔야합니까?
Gaurav

1

넌 말할 수있다

 $name ne ""

대신에

 length $name > 0

7
그래도 경고가 표시됩니다. 사람들이 정의를 먼저 확인하는 이유는 '초기화되지 않은 값'경고를 피하기 위해서입니다.
brian d foy

1

단순하고 우아한 방식으로 반복적 인 작업을 수행하는 것이 항상 가능한 것은 아닙니다.

여러 프로젝트에서 복제되는 공통 코드가있을 때 항상 수행하는 작업을 수행하십시오.

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)..


2
망치로 파리를 죽이는 것과 같지 않나요?
Zoran Simic

4
@Zoran 아니요. 이와 같이 코드를 팩토링하면 복잡한 조건이 여러 곳에서 복제되는 것이 좋습니다. 그것은 코끼리를 죽이기 위해 핀 프릭을 사용하는 것과 같습니다. @daotoad : 사용을 강조하기 위해 대답을 줄여야한다고 생각합니다 Scalar::MoreUtils.
Sinan Ünür

@Zoran : Scalar :: MoreUtils는 종속성이없는 매우 가벼운 모듈입니다. 그 의미도 잘 알려져 있습니다. CPAN에 알레르기가없는 경우 사용을 피할 이유가별로 없습니다.
Adam Bellaire

1
@Chris Lutz, 그래, 안돼. 하지만 프로토 타입은 반쯤 깨져서 프로토 타입 시행을 쉽게 깨뜨릴 수있는 방법이 있습니다. 예를 들어, 형편 없거나 오래된 튜토리얼은 &함수를 호출 할 때시길 사용을 계속 권장합니다 . 그래서 모든 작업을 프로토 타입에 의존하지 않는 경향이 있습니다. 오류 메시지에 "정말 의미하지 않는 한 하위 호출에서 &시길 사용을 중단"할 수 있다고 생각합니다.
daotoad

1
프로토 타입을 perl 컴파일러에 대한 힌트로 생각하는 것이 더 쉬우므로 구문 분석 방법을 알 수 있습니다. 그들은 인수를 검증하기 위해 존재하지 않습니다. 사람들의 기대면에서 깨질 수 있지만 많은 것들이 있습니다. :)
brian d foy

1

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

-2

어때

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

이것은 $name숫자 값 0 또는 문자열 '0'인 경우 false를 반환 하지만 다른 모든 경우에는 동일하게 작동하므로 원래 버전과 완전히 동일하지 않습니다 .

Perl 5.10 (이상)에서 적절한 접근 방식은 대신 defined-or 연산자를 사용하는 것입니다.

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

이것은 $name그것이 사실인지 아닌지 가 아닌 정의 여부에 따라 길이를 구할 것인지를 결정할 것이므로 0 / '0'는 이러한 경우를 올바르게 처리하지만 많은 사람들이 사용할 수있는 것보다 최신 버전의 펄이 필요합니다.


2
왜 망가 졌다고 만 말하면서 망가진 해결책으로 이끄는가?
brian d foy

내가 또한 언급했듯이 5.10은 "많은 사람들이 사용할 수있는 것보다 더 최신 버전의 펄"이기 때문입니다. YMMV,하지만 "이것은 사용할 수있는 99 % 솔루션입니다.하지만 사용할 수있는 더 나은 솔루션이 있습니다. 아마도 사용할 수없는 솔루션이 있습니다."가 "완벽한 솔루션이 있습니다.하지만 아마도 가능할 것입니다." t 사용하십시오. 따라서 대체로 얻을 수있는 대안이 있습니다. "
Dave Sherohman

1
이전 펄을 사용하더라도 고장난 솔루션 대신 작동하는 솔루션을 가질 수 있습니다.
brian d foy

-3
if ($ name)
{
    #since undef와 ''둘 다 false로 평가됩니다. 
    # 이것은 문자열이 정의되고 비어 있지 않은 경우에만 작동합니다 ...
    # $ name = "0"과 같은 무언가를 기대하지 않는 한 이것은 거짓입니다.
    # $ name = "00"이 거짓이 아니라는 점에 유의하세요.
}

1
불행히도 $ name = 0 일 때 이것은 거짓입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.