Reputation: 5612
<?php
$val = '245E1';
var_dump($val); // return string(5) "245E1"
$n = is_numeric($val);
var_dump($n); // return bool(true)
Problem: is_numeric return TRUE
Questions:
How to treat $val as string, not a number?
How to disable exponent interpretation?
Upvotes: 6
Views: 2356
Reputation: 2724
I had some struggles with this and came up with something:
function is_really_numeric($string) {
return preg_match('#^(?!0[1-9])\d*\.?(?!\.)\d+$#', $string);
}
And in action:
<?php
$val = '245E1';
if (preg_match('#^(?!0[1-9])\d*\.?(?!\.)\d+$#', $val)) {
settype($val, 'float');
}
var_dump($val);
?>
This would not interpret "0123", "24e51", ".", or "1.2.3.4" as a numeric value.
https://regex101.com/r/PtPM8l/3
Upvotes: 2
Reputation: 3804
If you want to specifically test if it's truely an integer number (without the exponential part), you can do
$a = '245E1';
$b = '24';
$isNumeric = $a == (int)$a; //false
$isNumeric = $b == (int)$b; //true
$isNumeric = is_int($b) || is_string($b) && ctype_digit($b);
Or in general, for floating number and other cases
$a = '245E1';
$b = '2.4';
$isNumeric = (float)$a == $a && strlen($a) == strlen((float)$a); //false
$isNumeric = (float)$b == $b && strlen($b) == strlen((float)$b); //true
Upvotes: 0
Reputation: 4889
From the manual on is_numeric(), you'll notice there are plenty of characters that can go in:
Numeric strings consist of optional sign, any number of digits, optional decimal part and optional exponential part. Thus +0123.45e6 is a valid numeric value. Hexadecimal (e.g. 0xf4c3b00c), Binary (e.g. 0b10100111001), Octal (e.g. 0777) notation is allowed too but only without sign, decimal and exponential part.
If you wish to check if a variable is type integer, you can use is_int(), and for floats, you can use is_float(). Note, though, that e.g. with is_int()
, your variable must actually be of type integer, not just a numeric string. You could also use ctype_digit() for this, but then your variable type would have to be a string; or specifically, not an integer that matches an ASCII character's ord()
.
It may be easiest to just use if (preg_match('#^\d+(\.\d+)?$#', $str))
to validate your variable of which-ever type as having only digits. (Remove the expression in brackets from the pattern if optional decimals are not welcome.)
The other option is ctype_digit((string) $str)
and casting the variable into a string type to avoid the ASCII mapping clash with integer types. This would not return true if you had decimal points.
100000 loops of ctype_digit
: 0.0340 sec. 100000 loops of preg_match
: 0.1120 sec. Use ctype_digit
if you want digits only and intend to do this a lot. Otherwise; whatever fits your style.
Upvotes: 3