0

How can I determine if a string can be an integer in Python. For example: if I write functions named digit() and nondigit(). The string must be either just digits (1-9) or letters.

str1 = '4582'
str1.digit() == True
str2 = '458dfr'
str2.digit() == False
str3 = 'abcd'
str3.nondigit() == True
str4 = '258edcx'
str4.nondigit() == False
user3552506
  • 45
  • 1
  • 1
  • 7

4 Answers4

5

str objects have an isdigit method which accomplishes one of your tasks. From a broader perspective, it's better to just try it and see:

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

For example, " 1234 ".isdigit() is False (there are spaces), but python can convert it to an int, so my digit function is True.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • +1, but note `" 1234 ".strip().isdigit()` would accomplish the same goal without raising a (relatively) expensive exception. – That1Guy Apr 22 '14 at 17:14
  • @That1Guy: OP did not mention this, but I wouldn't be surprised if he also wants `"-8"` to evaluate to `True`. Also, don't worry so much about performance. Write what is clear and if it's too slow then profile and refactor. – Steven Rumbalski Apr 22 '14 at 17:26
  • Go with `is.digit()`, it is much faster and "prettier", I added the benchmark as an answer below –  Apr 22 '14 at 17:36
  • @SebastianRaschka: Note that the OP asked "How can I determine if a string can be an integer in Python." While the OP interprets that as being covered by two functions `digit` and `notdigit`, the correct answer as to whether a string can be an integer is to try to make an integer out of it, faster and "prettier" aside. – Steven Rumbalski Apr 22 '14 at 22:25
  • @StevenRumbalski -- I assume you mean `str.isdigit` rather than `is.digit`. I mentioned `str.isdigit`, but it is nowhere near as correct as just trying and catching the exception. Since it doesn't check for things like padding whitespace and leading `'-'` signs, it's not surprising that it is quicker... – mgilson Apr 22 '14 at 22:39
  • Okay, then let's go with 'easier' instead of 'faster' or 'prettier' :) –  Apr 22 '14 at 22:39
  • @mgilson: Actually, I was quoting from the OP's question (except that I called his `nondigit` mythical function as `notdigit`). I agree that it is "nowhere near as correct as just trying and catching the exception", which is what I was trying to say. – Steven Rumbalski Apr 23 '14 at 21:40
2

There's a builtin for that.

'4582'.isdigit() == True
'458dfr'.isdigit() == False

"Under the hood" this probably looks a lot like:

def isdigit(self):
    return all(ch in "0123456789" for ch in self)

That said, if you're trying to USE it as an int, just use it as an int.

data = "123456"
try:
    data = int(data)
except ValueError:
    # handle this if your data is not a number

Never test for something to see if it's able to be transformed THEN try to transform it. This goes for int casts as well as checking for the existence of a file before opening it. It creates a race condition where if data can be turned to a number when you check but then another thread takes over and changes it before it gets cast to int you get an error. Similarly with files if you check that the file exists but something deletes it before it can be opened, you're SOL.

Instead, do the thing you're trying to do, and "ask forgiveness" if it causes an error. It's Easier to Ask Forgiveness than Permission.

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
0

Use .isdigit() for a built-in way to do that.

>>> string = 'hello'
>>> num = '98'
>>> string.isdigit()
False
>>> num.isdigit()
True
>>> 

You can also create your own function:

>>> def digit(num):
...     try:
...             int(num)
...             return True
...     except ValueError:
...             return False
... 
>>> digit('45')
True
>>> digit('hello')
False
>>> 
A.J. Uppal
  • 19,117
  • 6
  • 45
  • 76
0

I now benchmarked the different approaches. is.digit() is way faster, and depending on what you do with it (e.g., large iterations) it might be worthile using it over an own function. (And it looks prettier btw.)

I put it into a IPython notebook if you want to run it on your machine:

And here are the results if:

import timeit

def string_is_int(a_str):
    try:
        int(a_str)
        return True
    except ValueError:
        return False

an_int = '123'
no_int = '123abc'

%timeit string_is_int(an_int)
%timeit string_is_int(no_int)
%timeit an_int.isdigit()
%timeit no_int.isdigit()

1000000 loops, best of 3: 401 ns per loop
100000 loops, best of 3: 3.04 µs per loop
10000000 loops, best of 3: 92.1 ns per loop
10000000 loops, best of 3: 96.3 ns per loop

Also, I have tested the more general case:

import timeit

def string_is_number(a_str):
    try:
        float(a_str)
        return True
    except ValueError:
        return False

a_float = '1.234'
no_float = '123abc'

a_float.replace('.','',1).isdigit()
no_float.replace('.','',1).isdigit()


%timeit string_is_number(an_int)
%timeit string_is_number(no_int)
%timeit a_float.replace('.','',1).isdigit()
%timeit no_float.replace('.','',1).isdigit()

1000000 loops, best of 3: 400 ns per loop
1000000 loops, best of 3: 1.15 µs per loop
1000000 loops, best of 3: 452 ns per loop
1000000 loops, best of 3: 394 ns per loop