[perl] How do I tell if a variable has a numeric value in Perl?

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.

This question is related to perl numbers

The answer is


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.


I found this interesting though

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

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";
}

If the bitwise feature is enabled, that makes & only a numeric operator and adds a separate string &. operator, you must disable it:

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

(bitwise is available in perl 5.022 and above, and enabled by default if you use 5.028; or above.)


Try this:

If (($x !~ /\D/) && ($x ne "")) { ... }

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

This is a slight variation on Veekay's answer but let me explain my reasoning for the change.

Performing a regex on an undefined value will cause error spew and will cause the code to exit in many if not most environments. Testing if the value is defined or setting a default case like i did in the alternative example before running the expression will, at a minimum, save your error log.


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


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}; }

Not perfect, but you can use a regex:

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

rexep not perfect... this is:

use Try::Tiny;

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

A simple (and maybe simplistic) answer to the question is the content of $x numeric is the following:

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

It does a textual comparison of the original $x with the $x converted to a numeric value.


Personally I think that the way to go is to rely on Perl's internal context to make the solution bullet-proof. A good regexp could match all the valid numeric values and none of the non-numeric ones (or vice versa), but as there is a way of employing the same logic the interpreter is using it should be safer to rely on that directly.

As I tend to run my scripts with -w, I had to combine the idea of comparing the result of "value plus zero" to the original value with the no warnings based approach of @ysth:

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

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.


You can use Regular Expressions to determine if $foo is a number (or not).

Take a look here: How do I determine whether a scalar is a number