views:

2620

answers:

5

Hi,

Is there any way to tell whether a string represents an integer (e.g., '3', '-17' but not '3.14' or 'asfasfas') Without using a try/except mechanism?

is_int('3.14') = False
is_int('-7')   = True

Thanks,

Adam

A: 

If you only deal with numeric values, one method could be to compare the int() and float() casts, but this will break when testing a string. (not to mention this can be expensive on large sets)

def isinteger(x):
    return int(x) == float(x)
-1 because the question specifically asks about testing a string.
Bryan Oakley
+11  A: 

with positive integers you could use .isdigit:

>>> '16'.isdigit()
True

it doesn't work with negative integers though. suppose you could try the following:

>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True

it won't work with '16.0' format, which is similar to int casting in this sense.

edit:

def check_int(s):
    if s[0] in ('-', '+'):
     return s[1:].isdigit()
    return s.isdigit()
SilentGhost
Does isnumeric return true for floats too?
Skurmedel
Sorry, I skipped the last sentence.
Skurmedel
nope .
SilentGhost
this doesn't handle "+17" without an additional special case.
Bryan Oakley
You have to test for BOTH cases: lambda s: s.isdigit() or (s.startswith('-') and s[1:].isdigit())
Roberto Liffredo
@Roberto: of course you should! and I'm sure you're capable of doing so!
SilentGhost
This will validate "08" which will break your Python source.
Triptych
`>>> int('08') 8`
SilentGhost
@SilentGhost - you're right. I noticed that right after posting that comment. But also, int(' + 08 ') == 8
Triptych
not in py3k :)
SilentGhost
+9  A: 

Use a regular expression:

import re
def RepresentsInt(s):
    return re.match(r"[-+]?\d+$", s) is not None

If you must accept decimal fractions also:

def RepresentsInt(s):
    return re.match(r"[-+]?\d+(\.0*)?$", s) is not None

For improved performance if you're doing this often, compile the regular expression only once using re.compile().

Greg Hewgill
+1: reveals that this is horrifyingly complex and expensive when compared with try/except.
S.Lott
I feel this is essentially a slower, custom version of the 'isnumeric' solution offered by @SilentGhost.
Greg
@Greg: Since the @SilentGhost doesn't cover signs correctly, this version actually works.
S.Lott
The re module caches the compiled regex anyway.
Triptych
@S.Lott: surely, anyone capable of posting on SO, would be able to extend my example to cover signs.
SilentGhost
+3  A: 

Greg Hewgill's approach was missing a few components: the leading "^" to only match the start of the string, and compiling the re beforehand. But this approach will allow you to avoid a try: exept:

import re
INT_RE = re.compile(r"^[-]?\d+$")
def RepresentsInt(s):
    return INT_RE.match(str(s)) is not None

I would be interested why you are trying to avoid try: except?

Nowell
A matter of style. I think that "try/except" should be used only with actual errors, not with normal program flow.
Adam Matan
@Udi Pasmon: Python makes fairly heavy use of try/except for "normal" program flow. For example, every iterator stops with a raised exception.
S.Lott
-1 : Although your hint at compiling the regex is right, you're wrong in critizising Greg in the other respect: re.match matches against the **start** of the string, so the ^ in the pattern is actually redundant. (This is different when you use re.search).
ThomasH
S.Lott - Is this considered reasonable flow in python? How does this differs from other languages? Perhaps it's worth a separate question.
Adam Matan
Python's heavy use of try/except has been covered here on SO. Try a search for '[python] except'
S.Lott
+8  A: 

If you're really just annoyed at using try/excepts all over the place, please just write a helper function:

def RepresentsInt(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False

It's going to be WAY more code to exactly cover all the strings that Python considers integers. I say just be pythonic on this one.

Triptych