简体   繁体   中英

PHP is_numeric - false when Exponent in string

<?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:

  1. How to treat $val as string, not a number?

  2. How to disable exponent interpretation?

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 (eg 0xf4c3b00c), Binary (eg 0b10100111001), Octal (eg 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 eg 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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM