tags:

views:

163

answers:

9

Do you know of a function that can check if a string holds an integer?

Here's how I'd expect it to work:

holds_int("23") // should return true.  
holds_int("2.3") // should return false.  
holds_int("qwe") // should return false.
A: 

http://www.php.net/manual/en/function.is-numeric.php

eyescream
From the OP's Example, it seems he wants strictly integers. `is_numeric()` returns true for floats, so the `is_int()` seems a better option.
st0le
From manual: var_dump(is_int("23")); -> bool(false)
eyescream
+10  A: 
if((string)(int)$var == $var) {
    echo 'var is an integer or a string representation of an integer';
}

Example results:

var_dump( test(1)             ); // TRUE
var_dump( test('1')           ); // TRUE
var_dump( test('1.0')         ); // TRUE
var_dump( test('1.1')         ); // false
var_dump( test('0xFF')        ); // false
var_dump( test('0123')        ); // TRUE
var_dump( test('01090')       ); // TRUE
var_dump( test('-1000000')    ); // TRUE
var_dump( test('+1000000')    ); // TRUE
var_dump( test('2147483648')  ); // false
var_dump( test('-2147483649') ); // false
Jhong
this should test with `===` and make sure the number is inside the integer range
Gordon
=== won't work if $var actually is an integer. == will, regardless of whether it is a string or an int. OP didn't ask for that specifically, but it seems a bit perverse to return false if it actually is an integer.
Jhong
There's also no point in the additional check for the PHP_INT_MAX -- the above will return false if the integer is out of range anyway. Why add the additional check?
Jhong
I dont think so: the OP asked for if *string* holds *integer*. If you pass in an integer, it's not a string, so ...
Gordon
@Gordon: Casting to integer will always yield a valid integer.
Gumbo
@Gumbo Ok, I stand corrected. You dont need the bitrange check then. And let's leave it up to the OP to decide if he needs `===` or `==` comparison. There is edge cases, e.g. '1.0', hex and octals.
Gordon
Thanks for the edits :-)
Jhong
A: 

Other option

function holds_int($str)
   {
   return preg_match("/^-?[0-9]+$/", $str);
   }
nico
This (in its current form) also doesn't account for negative integers.
VolkerK
@VolkerK: I was editing it, now it does
nico
Why the downvote? This does exactly what the OP asked for.
nico
regex is a fairly resource-intensive solution to an ostensibly simple problem (I didn't downvote you mind).
Jhong
Didn't downvote but with the current version the function returns true(1) for "23-5-".
VolkerK
Now your regex allows `12-34`. You should use `/^-?[0-9]+$/`. If you want to reject leading zeros (which you should) use `/^-?[1-9][0-9]*$/`.
nikic
good point about the minus in the middle, updated the code!NB: I wasn't complaining because of the downvote per se, just asking why it was not correct. As for regexp being resource intensive it really depends how often this gets called, it may not be good in certain situation but it may be absolutely ok for others.
nico
@nikic: I wouldn't reject leading zeros, "05" is a valid integer containing string IMHO.
nico
Regular Expressions: Now You Have Two Problems
webjunkie
I beg to differ
nico
A: 

There may be two cases-

  1. You need to check for exact string format of a number(most of ans is about this one)

  2. You want to check, whether a string contains a specific number or not

    preg_match('/'.$matching_number.'/',$container_string);

Sadat
+1  A: 

Dont want to accidently turn Jhong's answer into a CW, so for the record here is the results when testing with === instead of ==.

function test($var) {
    return ((string)(int)$var === $var);
}

var_dump( test(1)             ); // returns false vs TRUE
var_dump( test('1')           ); // returns TRUE
var_dump( test('1.0')         ); // returns false vs TRUE
var_dump( test('1.1')         ); // returns false 
var_dump( test('0xFF')        ); // returns false
var_dump( test('0123')        ); // returns false vs TRUE
var_dump( test('-0123')       ); // returns false vs TRUE
var_dump( test('-1000000')    ); // returns TRUE
var_dump( test('+1000000')    ); // returns false vs TRUE
var_dump( test('2147483648')  ); // returns false
var_dump( test('-2147483649') ); // returns false
Gordon
1.0 (float) and 0123 (invalid) are better results here than my version -- I hadn't considered them!
Jhong
@Jhong using `==` will also return true for hex `0xFF` and scientific notation `-1.3e3` (e.g. both when not used as string, false if used as string)
Gordon
A: 

comparison.php:

<?php
function is_numeric_int($s)
{
  return (strval(intval($s)) === $s);
}

function print_ini($s)
{
  echo "$s: " . ( is_numeric_int($s) ? 'true' : 'false' ) . "\n";
}

print_ini('qwe');
print_ini('23');
print_ini('-23');
print_ini('23.0');
print_ini('-23.0');
?>

Test run:

$ php comparison.php 
qwe: false
23: true
-23: true
23.0: false
-23.0: false
clacke
A: 
function is_stringified_int($str) {
    return isset($str[0]) && false !== strpos('-0123456789', $str[0]) && !isset($str[strcspn($str, '0123456789', 1)]);
}

What it does: First checks that first string offset is set. ('' isn't an int.) Then is checks whether the first string offset is a digit or -. And than it checks that all the other characters are only digits.

Little bit hacky, but doesn't use regex. I don't even know, whether this is faster than regex.

nikic
A: 

is_int is the only what it's meant to do this work.

jack
+1  A: 

Sorry if this question has been answered but this has worked for me in the past:

First check if the string is_numeric. if it is add a 0 to the value to get PHP to covert the string to its relevant type. Then you can check if it's an int with is_int. Quick and dirty but it works for me...

$values = array(1, '2', '2.5', 'foo', '0xFF', 0xCC, 0644, '0777');

foreach ($values as $value) {
  $result = is_numeric($value) && is_int(($value + 0)) ? 'true' : 'false';
  echo $value . ': ' . $result . '<br />';
}

Results:

1: true
2: true
2.5: false
foo: false
0xFF: true
204: true
420: true
0777: true

The only problem is that it will evaluate octal values wrapped in a string literally, i.e: '0123' will simply become 123. But that's easy to address :)

Darragh