tags:

views:

5065

answers:

9

Is there a simple way in Perl that will allow me to determine if a given variable is numeric? Something along the lines of:

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

would be ideal. A technique that won't throw warnings when the -w switch is being used is certainly preferred.

+1  A: 

Not perfect, but you can use a regex:

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

Usually number validation is done with regular expressions. This code will determine if something is numeric as well as check for undefined variables as to not throw warnings:

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

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

Here's some reading material you should look at.

superjoe30
This misses many cases, including scientific notation.
brian d foy
+1  A: 

I don't believe there is anything builtin to do it. For more than you ever wanted to see on the subject, see Perlmonks on Detecting Numeric

jsight
A: 

A slightly more robust regex can be found in Regexp::Common.

It sounds like you want to know if Perl thinks a variable is numeric. Here's a function that traps that warning:

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

Another option is to turn off the warning locally:

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

Note that non-numeric variables will be silently converted to 0, which is probably what you wanted anyway.

Jon Ericson
+8  A: 

Check out the CPAN module Regexp::Common. I think it does exactly what you need and handles all the edge cases (e.g. real numbers, scientific notation, etc). e.g.

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

Use Scalar::Util::looks_like_number() which uses the internal Perl C API's looks_like_number() function, which is probably the most efficient way to do this.

Example:

#!/usr/local/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);

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

Gives this output:

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

see also:

perldoc Scalar::Util
perldoc perlapi
nohat
And as usual with perl docs, finding the actual *definition* of what the function does is rather difficult. Following the trail `perldoc perlapi` tells us: Test if the content of an SV looks like a number (or is a number). "Inf" and "Infinity" are treated as numbers (so will not issue a non-numeric warning), even if your atof() doesn't grok them. Hardly a testable spec...
Day
+2  A: 

The Scalar::Util answer given above by nohat is by far the best way to do this. Regular Expressions are always prone to there being unforeseen corner cases that are not caught.

In answer to Derek's earlier comment about there being nothing "built-in" to perl, it's worth noting that the Scalar::Util module ships with Perl itself since version 5.8 (2002 era) so it's already installed and can effectively be considered "core".

(meta: presumably my karma is too low to edit the Scalar::Util reply itself to add this, otherwise I'd have done that.)

ollyg
could have added a comment there.
glenn jackman
+1  A: 

People forget about scientific notation and that complicates things quite a bit. Is Nan numeric?

Anne E. Mouse
Well, NaN stands for "not a number", so do you think it's a number? :)
brian d foy
Yet it is a value that might appear in a list of outputs from caclculations and since it has informational value about the result of numeric operations, you might not want to drop it from a list of numeric values.
Anne E. Mouse
A: 

The original question was how to tell if a variable was numeric, not if it "has a numeric value".

There are a few operators that have separate modes of operation for numeric and string operands, where "numeric" means anything that was originally a number or was ever used in a numeric context (e.g. in $x = "123"; 0+$x, before the addition, $x is a string, afterwards it is considered numeric).

One way to tell is this:

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