58

I have a string like

"xdtwkeltjwlkejt7wthwk89lk"

how can I get the index of the first digit in the string?

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
AP257
  • 89,519
  • 86
  • 202
  • 261

14 Answers14

86

Use re.search():

>>> import re
>>> s1 = "thishasadigit4here"
>>> m = re.search(r"\d", s1)
>>> if m:
...     print("Digit found at position", m.start())
... else:
...     print("No digit in that string")
... 
Digit found at position 13
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
bgporter
  • 35,114
  • 8
  • 59
  • 65
  • 4
    In case anyone is interested in performance, I did some quit timeit work on a few different approaches - regular expressions are the fastest: https://gist.github.com/1683249 – umbrae Jan 26 '12 at 15:21
  • 1
    What would you use instead of `m.start()` in order to get what digit is found (in this case 4)? – zanahorias Oct 05 '18 at 06:35
  • 2
    @zanahorias you can use `m.group(0)` – Ankit Jaiswal Nov 02 '18 at 09:37
  • 3
    It has been a long time since @umbrae's benchmark and currently on Python 3.7.8 the `isdigit()` method is consistently faster for me by about 5-6%. – dtasev Nov 11 '20 at 15:39
39

Here is a better and more flexible way, regex is overkill here.

s = 'xdtwkeltjwlkejt7wthwk89lk'

for i, c in enumerate(s):
    if c.isdigit():
        print(i)
        break

output:

15

To get all digits and their positions, a simple expression will do

>>> [(i, c) for i, c in enumerate('xdtwkeltjwlkejt7wthwk89lk') if c.isdigit()]
[(15, '7'), (21, '8'), (22, '9')]

Or you can create a dict of digit and its last position

>>> {c: i for i, c in enumerate('xdtwkeltjwlkejt7wthwk89lk') if c.isdigit()}
{'9': 22, '8': 21, '7': 15}
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
21

Thought I'd toss my method on the pile. I'll do just about anything to avoid regex.

sequence = 'xdtwkeltjwlkejt7wthwk89lk'
i = [x.isdigit() for x in sequence].index(True)

To explain what's going on here:

  • [x.isdigit() for x in sequence] is going to translate the string into an array of booleans representing whether each character is a digit or not
  • [...].index(True) returns the first index value that True is found in.
alukach
  • 5,921
  • 3
  • 39
  • 40
10
import re
first_digit = re.search('\d', 'xdtwkeltjwlkejt7wthwk89lk')
if first_digit:
    print(first_digit.start())
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Christian
  • 1,499
  • 2
  • 12
  • 28
10

Seems like a good job for a parser:

>>> from simpleparse.parser import Parser
>>> s = 'xdtwkeltjwlkejt7wthwk89lk'
>>> grammar = """
... integer := [0-9]+
... <alpha> := -integer+
... all     := (integer/alpha)+
... """
>>> parser = Parser(grammar, 'all')
>>> parser.parse(s)
(1, [('integer', 15, 16, None), ('integer', 21, 23, None)], 25)
>>> [ int(s[x[1]:x[2]]) for x in parser.parse(s)[1] ]
[7, 89]
Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153
  • 11
    Surely overkill for this, but a nice recipe to be featured here! – jsbueno Dec 22 '10 at 16:05
  • 2
    @jsbueno: thanks, indeed an overkill (at least until you have to extend the pattern matching, sometimes I have a hard time understanding a regex I wrote two months before) :-) – Paulo Scardine Dec 22 '10 at 16:18
  • 3
    This answer taught me more about how to use simpleparse than any tutorial. – daybreak Dec 17 '15 at 05:12
7

To get all indexes do:

idxs = [i for i in range(0, len(string)) if string[i].isdigit()]

Then to get the first index do:

if len(idxs):
    print(idxs[0])
else:
    print('No digits exist')
Steven Eckhoff
  • 992
  • 9
  • 18
3

As the other solutions say, to find the index of the first digit in the string we can use regular expressions:

>>> s = 'xdtwkeltjwlkejt7wthwk89lk'
>>> match = re.search(r'\d', s)
>>> print match.start() if match else 'No digits found'
15
>>> s[15] # To show correctness
'7'

While simple, a regular expression match is going to be overkill for super-long strings. A more efficient way is to iterate through the string like this:

>>> for i, c in enumerate(s):
...     if c.isdigit():
...         print i
...         break
... 
15

In case we wanted to extend the question to finding the first integer (not digit) and what it was:

>>> s = 'xdtwkeltjwlkejt711wthwk89lk'
>>> for i, c in enumerate(s):
...     if c.isdigit():
...         start = i
...         while i < len(s) and s[i].isdigit():
...             i += 1
...         print 'Integer %d found at position %d' % (int(s[start:i]), start)
...         break
... 
Integer 711 found at position 15
moinudin
  • 134,091
  • 45
  • 190
  • 216
3

In Python 3.8+ you can use re.search to look for the first \d (for digit) character class like this:

import re

my_string = "xdtwkeltjwlkejt7wthwk89lk"

if first_digit := re.search(r"\d", my_string):
    print(first_digit.start())
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
2

I'm sure there are multiple solutions, but using regular expressions you can do this:

>>> import re
>>> match = re.search("\d", "xdtwkeltjwlkejt7wthwk89lk")
>>> match.start(0)
15
Massimiliano Torromeo
  • 1,801
  • 1
  • 15
  • 17
2

Here is another regex-less way, more in a functional style. This one finds the position of the first occurrence of each digit that exists in the string, then chooses the lowest. A regex is probably going to be more efficient, especially for longer strings (this makes at least 10 full passes through the string and up to 20).

haystack = "xdtwkeltjwlkejt7wthwk89lk"
digits   = "012345689"
found    = [haystack.index(dig) for dig in digits if dig in haystack]
firstdig = min(found) if found else None
kindall
  • 178,883
  • 35
  • 278
  • 309
0
def first_digit_index(iterable):
    try:
        return next(i for i, d in enumerate(iterable) if d.isdigit())
    except StopIteration:
        return -1

This does not use regex and will stop iterating as soon as the first digit is found.

Jacobo de Vera
  • 1,863
  • 1
  • 16
  • 20
0

you can use regular expression

import re
y = "xdtwkeltjwlkejt7wthwk89lk"

s = re.search("\d",y).start()
drhanlau
  • 2,517
  • 2
  • 24
  • 42
-1
import re
result = "  Total files:...................     90"
match = re.match(r".*[^\d](\d+)$", result)
if match:
    print(match.group(1))

will output

90
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
-1
instr = 'nkfnkjbvhbef0njhb h2konoon8ll'
numidx = next((i for i, s in enumerate(instr) if s.isdigit()), None)
print(numidx)

Output:

12

numidx will be the index of the first occurrence of a digit in instr. If there are no digits in instr, numidx will be None.

I didn't see this solution here, and thought it should be.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Zack
  • 1
  • I'm not sure how you missed it, but this isn't any different from the [second most upvoted answer on this question](https://stackoverflow.com/a/4510805). – Boris Verkhovskiy Mar 12 '21 at 09:11