137

I have a string that starts with a number (from 0-9) I know I can "or" 10 test cases using startswith() but there is probably a neater solution

so instead of writing

if (string.startswith('0') || string.startswith('2') ||
    string.startswith('3') || string.startswith('4') ||
    string.startswith('5') || string.startswith('6') ||
    string.startswith('7') || string.startswith('8') ||
    string.startswith('9')):
    #do something

Is there a cleverer/more efficient way?

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
Illusionist
  • 5,204
  • 11
  • 46
  • 76
  • 1
    If the question is asked: "Is this too repetitive?", the chances are -- in a high level language -- the answer is "Why, yes, it sure is". [Be lazy!](http://c2.com/cgi/wiki?LazinessImpatienceHubris) –  Apr 07 '11 at 07:46
  • 57
    You missed `string.startswith('1')`. – MAK Apr 07 '11 at 08:40
  • 2
    @Illusionist As it is written, your question means that you want to detect the strings that begin with only ONE digit. If so, the only right answer among the following ones, are not the ones using ``s[0]`` or ``s[:1]`` but the solution of John Machin: ``if s.startswith(tuple('0123456789'))``. Moreover, this solution raises error when it happens that **s** is a sequence like a tuple or list, which cases produce the same result as if it was a string. - Another solution is a regex whose pattern is **'\d(?=\D)'** but use of regex is superfluous here. – eyquem Aug 20 '11 at 11:10
  • 4
    Just being pedantic: `string` is a module in the standard library and probably shouldn't be used as a variable name. http://docs.python.org/2/library/string.html – gak Mar 14 '13 at 23:16

12 Answers12

241

Python's string library has isdigit() method:

string[0].isdigit()
plaes
  • 31,788
  • 11
  • 91
  • 89
33
>>> string = '1abc'
>>> string[0].isdigit()
True
Jaroslav Bezděk
  • 6,967
  • 6
  • 29
  • 46
jcomeau_ictx
  • 37,688
  • 6
  • 92
  • 107
  • 1
    I'm not a python guy, so perhaps you can help me on this: will this function bomb on "", where there is no `string[0]`? – corsiKa Apr 07 '11 at 07:43
  • yep, it sure will. you could use (string or 'x')[0].isdigit() to fix it for '' or None – jcomeau_ictx Apr 07 '11 at 07:45
  • 34
    You could try `string[:1].isdigit()`, which will quit happily deal with an empty string. – Simon Callan Apr 07 '11 at 08:23
  • So why not editing the answer to reflect @SimonCallan's proposal? – MERose Oct 29 '15 at 14:59
  • 2
    because that's not my answer; mine is still better in the case where the programmer wishes an exception to be thrown on an empty string. – jcomeau_ictx Oct 29 '15 at 15:40
  • 1
    @jcomeau_ictx exactly right. never defensively program. if the string is unexpectedly blank, that _should_ error out and shouldn't be automatically handled anyway. Some schools of thought say you should gracefully handle and catch exceptions that aren't critical as warning and keep the program going. I am not of this mindset for most use cases. Specificity in the functions and code you are writing helps mitigate the edge cases where you would need to code defensively more often. – james-see Sep 11 '17 at 03:36
26

Surprising that after such a long time there is still the best answer missing.

The downside of the other answers is using [0] to select the first character, but as noted, this breaks on the empty string.

Using the following circumvents this problem, and, in my opinion, gives the prettiest and most readable syntax of the options we have. It also does not import/bother with regex either):

>>> string = '1abc'
>>> string[:1].isdigit()
True

>>> string = ''
>>> string[:1].isdigit()
False
PascalVKooten
  • 20,643
  • 17
  • 103
  • 160
12

sometimes, you can use regex

>>> import re
>>> re.search('^\s*[0-9]',"0abc")
<_sre.SRE_Match object at 0xb7722fa8>
kurumi
  • 25,121
  • 5
  • 44
  • 52
9

Your code won't work; you need or instead of ||.

Try

'0' <= strg[:1] <= '9'

or

strg[:1] in '0123456789'

or, if you are really crazy about startswith,

strg.startswith(('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'))
John Machin
  • 81,303
  • 11
  • 141
  • 189
  • I would have upvoted you if there was only the solution with **startswith(a tuple)** . But the solutions with ``strg[:1]`` have two inconveniences: they don't raise an error if **s** may happen to be a list of strings, and they produce **True** if the string begins with SEVERAL digits. – eyquem Aug 20 '11 at 11:05
  • @eyquem _they produce True if the string begins with SEVERAL digits_ So? Other answers don't check for that, because it wasn't a requirement that it had to check that other chars weren't numeric. – Rob Grant Apr 17 '15 at 07:07
  • I _am_ crazy for `startswith` and did implement it this way in my code. Thank you. – james-see Jun 08 '16 at 18:21
  • One more startswith possibility... `startswith(tuple(str(i) for i in range(10)))` – Jérôme Jul 11 '16 at 10:56
  • `.isdigit()` is preferred – PascalVKooten Apr 10 '21 at 13:29
4

This piece of code:

for s in ("fukushima", "123 is a number", ""):
    print s.ljust(20),  s[0].isdigit() if s else False

prints out the following:

fukushima            False
123 is a number      True
                     False
Jaroslav Bezděk
  • 6,967
  • 6
  • 29
  • 46
eyquem
  • 26,771
  • 7
  • 38
  • 46
  • 4
    That is ugly. Use `s[:1].isdigit()` or `s and s[0].isdigit()` – John Machin Aug 20 '11 at 09:29
  • 1
    @John Machin What do you mean by 'ugly' ? Not readable ? I don't find your propositions here above more readable. ``s and s[0].isdigit()`` is even less readable in my opinion. Personally, I like the construct **... if ... else ...** Taking account of your remark, I would just improve it like that: ``s[0].isdigit() if s!="" else False`` – eyquem Aug 20 '11 at 10:59
2

You can also use try...except:

try:
    int(string[0])
    # do your stuff
except:
    pass # or do your stuff
One Face
  • 417
  • 4
  • 10
2

Using the built-in string module:

>>> import string
>>> '30 or older'.startswith(tuple(string.digits))

The accepted answer works well for single strings. I needed a way that works with pandas.Series.str.contains. Arguably more readable than using a regular expression and a good use of a module that doesn't seem to be well-known.

ramiro
  • 878
  • 9
  • 20
1

Here are my "answers" (trying to be unique here, I don't actually recommend either for this particular case :-)

Using ord() and the special a <= b <= c form:

//starts_with_digit = ord('0') <= ord(mystring[0]) <= ord('9')
//I was thinking too much in C. Strings are perfectly comparable.
starts_with_digit = '0' <= mystring[0] <= '9'

(This a <= b <= c, like a < b < c, is a special Python construct and it's kind of neat: compare 1 < 2 < 3 (true) and 1 < 3 < 2 (false) and (1 < 3) < 2 (true). This isn't how it works in most other languages.)

Using a regular expression:

import re
//starts_with_digit = re.match(r"^\d", mystring) is not None
//re.match is already anchored
starts_with_digit = re.match(r"\d", mystring) is not None
0

You could use regular expressions.

You can detect digits using:

if(re.search([0-9], yourstring[:1])):
#do something

The [0-9] par matches any digit, and yourstring[:1] matches the first character of your string

Tovi7
  • 2,793
  • 3
  • 23
  • 27
-2

Use Regular Expressions, if you are going to somehow extend method's functionality.

Ilya Smagin
  • 5,992
  • 11
  • 40
  • 57
-5

Try this:

if string[0] in range(10):
bradley.ayers
  • 37,165
  • 14
  • 93
  • 99