Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Is there better way to find out if a scalar is a number then running it threw /\D/ ??

Replies are listed 'Best First'.
RE: Number?
by extremely (Priest) on Oct 25, 2000 at 09:02 UTC
    Oh, try that with "-1.35353E-2". It's a number but your test fails.

    Since perl will treat any string as a number and do its very best to make the right choice, you must understand exactly what numbers you are testing for. If you are only interested in positive integers, "/\D/" is fine.

    Otherwise you will have to craft a craftier regexp for your particular problem. You can look for non valid chars like this: if ($testit =~ /[^0-9.Ee+-]/) { print "Is bad!"} but keep in mind that fails on stuff like "--3E3E3E++".

    The Cookbook has this headache inducer for the worst of circumstances:

    if ($t =~/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) { print "Is Good!"; }

    Use that at your own risk tho...

    --
    $you = new YOU;
    honk() if $you->love(perl)

Re: Number?
by runrig (Abbot) on Oct 25, 2000 at 04:45 UTC
    I don't know if its better, but TMTOWTDI (I assume by 'number', you mean 'integer'):
    while (<>) { chomp; # All do the same thing print "$_ is a number" unless tr/0-9//c; print "$_ is a number" unless /\D/; print "$_ is a number" if /^\d+$/; }
    All in all, /\D/ is probably as good as any, but if you're really curious you can benchmark :-)
      <pedantic type=unicode>

      Not so fast! Believe it or not, \d matches 178 characters in utf8. [1]

      So, while your second two solutions are equivalent, the first one is only correct if you know you're dealing with ASCII.

      [1]: Just in case you don't believe me :-)

      [~] $ perl -anle'next if/[^\s\da-f]/i;$t+=hex($F[1])-hex($F[0]); END{print$t}' bleadperl/lib/unicode/Is/Digit.pl 178

      </pedantic>

      -dlc

        I would /expect/ that the regexp \d would match numbers, and numbers only. If 178 items in Unicode match, why? Are these just different ways of representing numbers in other languages perhaps? Perhaps things like 1/2 or 1/4? Or are you generating Unicode that is overly long, with different Unicode representations for the same numbers?

        Does anyone have any explanation for why this would be the case? Does it even violate the assumption that \d matches numbers?

markjugg-- using int to test numberness
by markjugg (Curate) on Oct 25, 2000 at 07:34 UTC
    I think using 'int' does a good job of this:
    print "is number" if int($test);
    If $test = '5.55555' it works, but if $test = 'howdy', it doesn't.

    -mark

      Um, no... this is bad...
      perl -e 'print "yikes\n" if int("1upmanship")' perl -e 'print "Zero is a number.\n" if int("0")'

      prints yikes! but not the "Zero..." line. int() doens't test a number it truncates it to integer form. And since the number 0 is false the second line doesn't work. Treating a string that starts with numeral as a number causes perl to whack off the text and use the number. OUCH!

      --
      $you = new YOU;
      honk() if $you->love(perl)