Perl에서 변수에 숫자 값이 있는지 어떻게 알 수 있습니까?


83

주어진 변수가 숫자인지 확인할 수있는 간단한 방법이 Perl에 있습니까? 라인을 따라 뭔가 :

if (is_number($x))
{ ... }

이상적 일 것입니다. -w스위치를 사용할 때 경고를 표시하지 않는 기술 이 확실히 선호됩니다.

답변:


128

Scalar::Util::looks_like_number()내부 Perl C API의 looks_like_number () 함수를 사용 하는 것을 사용 하십시오. 이는 아마도이를 수행하는 가장 효율적인 방법 일 것입니다. 문자열 "inf"및 "infinity"는 숫자로 처리됩니다.

예:

#!/usr/bin/perl

use warnings;
use strict;

use Scalar::Util qw(looks_like_number);

my @exprs = qw(1 5.25 0.001 1.3e8 foo bar 1dd inf infinity);

foreach my $expr (@exprs) {
    print "$expr is", looks_like_number($expr) ? '' : ' not', " a number\n";
}

이 출력을 제공합니다.

1 is a number
5.25 is a number
0.001 is a number
1.3e8 is a number
foo is not a number
bar is not a number
1dd is not a number
inf is a number
infinity is a number

또한보십시오:


1
그리고 Perl 문서에서 평소와 같이 함수가하는 일의 실제 정의 를 찾는 것은 다소 어렵습니다. 추적을 따라 perldoc perlapi가면 다음과 같은 정보를 얻을 수 있습니다. SV의 내용이 숫자 (또는 숫자)인지 테스트합니다. "Inf"와 "Infinity"는 atof ()가 그다지 표시하지 않더라도 숫자로 취급됩니다 (숫자가 아닌 경고를 발행하지 않음). 거의 테스트 할 수없는 사양 ...
Day

3
Scalar :: Util의 설명은 괜찮습니다. looks_like_number는 입력이 Perl이 숫자로 취급 할 것인지를 알려줍니다. 이것이 반드시이 질문에 대한 최선의 대답은 아닙니다. atof에 대한 언급은 무관하고, atof는 CORE :: 또는 POSIX의 일부가 아닙니다 (atof 및 / is / POSIX의 일부를 포함하는 strtod를보고 있어야합니다). Perl이 숫자라고 생각하는 것이 유효한 숫자 입력이라고 가정합니다. C 함수에 대한 것은 분명히 매우 잘못되었습니다.
MkV

아주 좋은 함수 :) undef 및 숫자가 아닌 문자열의 경우 0을 반환하고 숫자 문자열의 경우 1을 반환하고 정수의 경우 4352를 반환하고 부동의 경우 8704를 반환합니다. :) 일반적으로> 0 숫자가 감지됩니다. 나는 그것을 리눅스에서 테스트했다.
Znik

1
나는 일반적으로이 함수를 좋아하지만 큰 int를 고려합니다. 1000000은 추적해야 할 많은 0이며 오류를 구걸하지만 1,000,000은 3 요소 배열로 간주되므로 Perl은 1_000_000을 허용하지만 looks_like_number ()는 아니오라고 말합니다. 나를 슬프게 만들어.
Dave Jacoby 2015

참고 : 같은 16 진수 문자열 0x12은 이 테스트에서 숫자로 간주 되지 않습니다 .
Adam Katz

23

CPAN 모듈 Regexp :: Common을 확인하십시오 . 나는 그것이 당신이 필요로하는 것을 정확히하고 모든 엣지 케이스 (예 : 실수, 과학적 표기법 등)를 처리한다고 생각합니다. 예 :

use Regexp::Common;
if ($var =~ /$RE{num}{real}/) { print q{a number}; }

23

원래 질문은 "숫자 값이 있는지"가 아니라 변수가 숫자인지 여부를 확인하는 방법이었습니다.

숫자 및 문자열 피연산자에 대해 별도의 작업 모드를 갖는 몇 가지 연산자가 있습니다. 여기서 "숫자"는 원래 숫자이거나 숫자 컨텍스트에서 사용 된 모든 것을 의미합니다 (예 :에서 $x = "123"; 0+$x, 덧셈 전은 $x문자열이고 그 뒤에는 문자열입니다. 숫자로 간주 됨).

한 가지 방법은 다음과 같습니다.

if ( length( do { no warnings "numeric"; $x & "" } ) ) {
    print "$x is numeric\n";
}

비트 기능이 활성화 &되어 숫자 연산자 만 생성되고 별도의 문자열 &.연산자가 추가되는 경우 비활성화해야합니다.

if ( length( do { no if $] >= 5.022, "feature", "bitwise"; no warnings "numeric"; $x & "" } ) ) {
    print "$x is numeric\n";
}

(bitwise는 perl 5.022 이상에서 사용할 수 있으며 사용자 use 5.028;이상인 경우 기본적으로 활성화됩니다 .)


훌륭 해요, 고맙습니다! 이것이 바로 제가 찾던 것입니다.
Juan A. Navarro

루틴을 하위로 패키지하면 첫 번째 숫자 값을 시도 할 때까지 숫자가 아닌 값을 올바르게 감지한다는 이상한 동작이 발생합니다. 또한 사실입니다. 그러나 length (...) 부분 주위에 eval을 넣으면 항상 잘 작동합니다. 내가 뭘 놓치고 있었는지 아십니까? sub numeric { $obj = shift; no warnings "numeric"; return eval('length($obj & "")'); }
yogibimbi 2013

@yogibimbi : 매번 동일한 $ obj 변수를 재사용하고 있습니다. 시도해보십시오 my $obj = shift;. 왜 평가인가?
ysth

죄송합니다. my $obj = shift물론 사용 했습니다. 내 코드에서 주석으로 올바르게 전송하지 않았으므로 약간 편집했습니다. 그러나 sub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); }동일한 오류가 발생합니다. 물론 은밀한 전역 변수를 사용하면 동작을 설명 할 수 있습니다.이 경우 정확히 예상 할 수 있지만 불행히도 그렇게 간단하지 않습니다. 또한 strict&에 의해 잡힐 것 warnings입니다. 나는 오류를 없애기 위해 필사적으로 eval을 시도했지만 작동했습니다. 더 깊은 추론이 아니라 시행 착오뿐입니다.
yogibimbi 2013

그것을 체크 아웃 : sub numeric { my $obj = shift; no warnings "numeric"; return length($obj & ""); } print numeric("w") . "\n"; #=>0, print numeric("x") . "\n"; #=>0, print numeric("1") . "\n"; #=>0, print numeric(3) . "\n"; #=>1, print numeric("w") . "\n"; #=>1. 길이 주위에 eval ( '')을 넣으면 마지막 인쇄에서 0이 표시됩니다. 그림을 이동.
yogibimbi 2013-04-25

9

질문에 대한 간단하고 단순한 대답 $x숫자 의 내용이 다음과 같다는 것 입니다.

if ($x  eq  $x+0) { .... }

숫자 값으로 변환 된 원본 $x과 텍스트 비교를 수행합니다 $x.


1
"-w"또는 "use warnings;"를 사용하면 경고가 발생합니다.
Derek Park

1
경고는 제거 할 수 있습니다 $x eq (($x+0)."")더 나쁜 문제가이 기능에서, "1.0"숫자되지 않는 것입니다 그러나
시조

1
$ x + 0 ne ''테스트하는 것으로 충분합니다. 0001로 문자를 보내면 올바른 번호가 숫자가 아닌 것으로 확인됩니다. '.05'텍스트 값을 테스트 할 때도 마찬가지입니다.
Znik

8

일반적으로 숫자 유효성 검사는 정규식으로 수행됩니다. 이 코드는 어떤 것이 숫자인지 확인하고 경고를 던지지 않도록 정의되지 않은 변수를 확인합니다.

sub is_integer {
   defined $_[0] && $_[0] =~ /^[+-]?\d+$/;
}

sub is_float {
   defined $_[0] && $_[0] =~ /^[+-]?\d+(\.\d+)?$/;
}

보아야 할 몇 가지 읽기 자료가 있습니다.


2
특히 질문자가 / simple /이라고 말했을 때 이것이 약간 벗어나 있다고 생각합니다. 과학적 표기법을 포함한 많은 경우는 거의 간단하지 않습니다. 모듈에 이것을 사용하지 않는 한 이러한 세부 사항에 대해 걱정하지 않을 것입니다. 때로는 단순함이 가장 좋습니다. 초콜릿 우유를 만들기 위해 젖소에 초콜릿 시럽을 넣지 마세요!
osirisgothra 2014.11.02

'.7'은 여전히 ​​놓친 가장 간단한 경우 중 하나 일 것입니다. float에 대해 /^[+-]?\d*\.?\d+$/를 사용하는 것이 좋습니다. 너무 과학적 표기법을 고려 내 변형, : /^[+-]?\d*\.?\d+(?:(?:e|E)\d+)?$/
아콩 카과

\d*\.?\d+부분은 ReDoS 위험을 유발 합니다. 내가 추천 /^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?$/또는 /^[+-]?(?!\.(?!\d)|$)\d*(?:\.\d*)?(?:(?<=[\d.])e[+-]?\d+)?$/i과학적 표기법 (포함 설명과 예제를 대신). 이 사용하는 배 부정적 예측도 같은 문자열을 방지 .하고 .e0숫자로 통과. 또한 e다음 숫자 를 확인하기 위해 긍정적 인 룩백을 사용합니다 .
아담 카츠

3

완벽하지는 않지만 정규식을 사용할 수 있습니다.

sub isnumber 
{
    shift =~ /^-?\d+\.?\d*$/;
}

andrewrk의 답변으로 같은 문제 : 많은 심지어 간단한 경우, 예를 벗어났습니다 '0.7'
아콩 카과


2

좀 더 강력한 정규식은 Regexp :: Common 에서 찾을 수 있습니다 .

Perl이 변수가 숫자라고 생각하는지 알고 싶은 것 같습니다. 다음은 해당 경고를 포착하는 함수입니다.

sub is_number{
  my $n = shift;
  my $ret = 1;
  $SIG{"__WARN__"} = sub {$ret = 0};
  eval { my $x = $n + 1 };
  return $ret
}

또 다른 옵션은 로컬에서 경고를 끄는 것입니다.

{
  no warnings "numeric"; # Ignore "isn't numeric" warning
  ...                    # Use a variable that might not be numeric
}

숫자가 아닌 변수는 자동으로 0으로 변환됩니다.


2

rexep이 완벽하지 않습니다 ... 이것은 :

use Try::Tiny;

sub is_numeric {
  my ($x) = @_;
  my $numeric = 1;
  try {
    use warnings FATAL => qw/numeric/;
    0 + $x;
  }
  catch {
    $numeric = 0;
  };
  return $numeric;
}


1

나는 이것이 흥미 롭다는 것을 알았다

if ( $value + 0 eq $value) {
    # A number
    push @args, $value;
} else {
    # A string
    push @args, "'$value'";
}

당신은 더 나은 설명이 필요합니다, 당신은 그것이 흥미 롭다고 생각하지만 그것이 op에 대답합니까? 당신의 대답은 질문에 대한 솔루션이 요구 이유를 설명하려고
쿠마 Saurabh을

예를 들어 내 $ value는 1이고 $ value + 0은 동일하게 유지됩니다. $ value 1과 비교하면 1이 1과 같습니다. $ value가 문자열 인 경우 "swadhi"라고 말하면 $ value + 0은 문자열 "swadhi"의 ASCII 값이됩니다. + 0 = 다른 숫자.
Swadhikar

0

개인적으로 갈 길은 Perl의 내부 컨텍스트에 의존하여 솔루션을 방탄으로 만드는 것이라고 생각합니다. 좋은 정규 표현식은 모든 유효한 숫자 값과 일치 할 수 있고 숫자가 아닌 값과 일치하지 않을 수 있지만 (또는 그 반대의 경우도 마찬가지) 인터프리터가 사용하는 동일한 논리를 사용하는 방법이 있으므로 직접 사용하는 것이 더 안전합니다.

스크립트를으로 실행하는 경향이 -w있으므로 "value plus 0"의 결과를 원래 값과 no warnings@ysth 의 기반 접근 방식을 비교하는 아이디어를 결합해야했습니다 .

do { 
    no warnings "numeric";
    if ($x + 0 ne $x) { return "not numeric"; } else { return "numeric"; }
}


-1

if ($ x && $ x! ~ m / \ D /) {} 또는 $ x = 0 if! $ x; if ($ x! ~ m / \ D /) {}

이것은 Veekay의 대답에 대한 약간의 변형이지만 변경에 대한 이유를 설명하겠습니다.

정의되지 않은 값에 대해 정규식을 수행하면 오류가 발생하고 대부분의 환경은 아니지만 대부분의 환경에서 코드가 종료됩니다. 값이 정의되어 있는지 테스트하거나 표현식을 실행하기 전에 대체 예제에서했던 것처럼 기본 케이스를 설정하면 최소한 오류 로그가 저장됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.