8

Possible Duplicate:
How do I tell if a variable has a numeric value in Perl?

I want to decide if a variable (value parsed from a string) is a number or not. How can I do that? Well, I guess /^[0-9]+$/ would work, but is there a more elegant version?

Community
  • 1
  • 1
petersohn
  • 11,292
  • 13
  • 61
  • 98

3 Answers3

26

You can use the looks_like_number() function from the core Scalar::Util module.
See also the question in perlfaq: How do I determine whether a scalar is a number/whole/integer/float?

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • 2
    This is arguably the most correct answer, since `Scalar::Util` hooks into the Perl API to actually ask Perl whether it thinks the variable looks numeric. Thus, for the common task of avoiding 'numeric' warnings, this will always work. Of course, sometimes it's better to simply say `no warnings 'numeric';`... – Adam Bellaire Sep 27 '10 at 20:32
24
if (/\D/)            { print "has nondigits\n" }
if (/^\d+$/)         { print "is a whole number\n" }
if (/^-?\d+$/)       { print "is an integer\n" }
if (/^[+-]?\d+$/)    { print "is a +/- integer\n" }
if (/^-?\d+\.?\d*$/) { print "is a real number\n" }
if (/^-?(?:\d+(?:\.\d*)?&\.\d+)$/) { print "is a decimal number\n" }
if (/^([+-]?)(?=\d&\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
                     { print "a C float\n" }

taken from here: http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Perl

CristiC
  • 22,068
  • 12
  • 57
  • 89
  • 2
    If you insist on a regex, get it from Regexp::Common :) – brian d foy Sep 27 '10 at 15:33
  • 1
    And, every one of these regexes that uses the $ anchor allows a newline at the end of the value. That's a mistake in perlfaq4 (I've now patched the docs to remove that mistake), where Rosetta Code got its example. This example, however, was to determine what sort of number it was, not that it was any sort of number. – brian d foy Sep 27 '10 at 15:41
  • Please correct me if I'm wrong - but it seems to me that in the particular case of checking for strictly digits (i.e., subset of numeric, since a numeric can have a decimal point and possibly a negative sign or even a positive sign, and also commas or some other visual grouping character used to group characters in threes for visual reading), then the "/\D/" is - where strings do exist that fail the digits-only test - always more efficient than "/^\d+$/" because "/\D/" is true on the scan of the first non-digit character. – Steve Greene Aug 20 '17 at 16:53
9

Using regex, it's good to use:

sub is_int { 
    $str = $_[0]; 
    #trim whitespace both sides
    $str =~ s/^\s+|\s+$//g;          

    #Alternatively, to match any float-like numeric, use:
    # m/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/

    #flatten to string and match dash or plus and one or more digits
    if ($str =~ /^(\-|\+)?\d+?$/) {
        print "yes  " . $_[0] . "\n";
    }
    else{
        print "no   " . $_[0] . "\n";
    }
}
is_int(-12345678901234);     #yes
is_int(-1);                  #yes
is_int(23.);                 #yes
is_int(-23.);                #yes
is_int(0);                   #yes
is_int(+1);                  #yes
is_int(12345678901234);      #yes
is_int("\t23");              #yes
is_int("23\t");              #yes
is_int("08");                #yes
is_int("-12345678901234");   #yes
is_int("-1");                #yes
is_int("0");                 #yes
is_int("+1");                #yes
is_int("123456789012345");   #yes
is_int("-");                 #no
is_int("+");                 #no 
is_int("yadz");              #no
is_int("");                  #no
is_int(undef);               #no
is_int("- 5");               #no
is_int("+ -5");              #no
is_int("23.1234");           #no
is_int("23.");               #no
is_int("--1");               #no
is_int("++1");               #no
is_int(" 23.5 ");            #no
is_int(".5");                #no
is_int(",5");                #no
is_int("%5");                #no
is_int("5%");                #no

Alternatively, you can use POSIX.

use POSIX;

if (isdigit($var)) {
    // integer
}
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Ruel
  • 15,438
  • 7
  • 38
  • 49