Pythonic way to find the last position in a string matching a negative regex

You can use re.finditer to extract start positions of all matches and return the last one from list. Try this Python code:

import re
print([m.start(0) for m in re.finditer(r'\D', 'uiae1iuae200')][-1])

Prints:

8

Edit: For making the solution a bit more elegant to behave properly in for all kind of inputs, here is the updated code. Now the solution goes in two lines as the check has to be performed if list is empty then it will print -1 else the index value:

import re

arr = ['', '123', 'uiae1iuae200', 'uiae1iuae200aaaaaaaa']

for s in arr:
    lst = [m.start() for m in re.finditer(r'\D', s)]
    print(s, '-->', lst[-1] if len(lst) > 0 else None)

Prints the following, where if no such index is found then prints None instead of index:

 --> None
123 --> None
uiae1iuae200 --> 8
uiae1iuae200aaaaaaaa --> 19

Edit 2: As OP stated in his post, \d was only an example we started with, due to which I came up with a solution to work with any general regex. But, if this problem has to be really done with \d only, then I can give a better solution which would not require list comprehension at all and can be easily written by using a better regex to find the last occurrence of non-digit character and print its position. We can use .*(\D) regex to find the last occurrence of non-digit and easily print its index using following Python code:

import re

arr = ['', '123', 'uiae1iuae200', 'uiae1iuae200aaaaaaaa']

for s in arr:
    m = re.match(r'.*(\D)', s)
    print(s, '-->', m.start(1) if m else None)

Prints the string and their corresponding index of non-digit char and None if not found any:

 --> None
123 --> None
uiae1iuae200 --> 8
uiae1iuae200aaaaaaaa --> 19

And as you can see, this code doesn't need to use any list comprehension and is better as it can just find the index by just one regex call to match.

But in case OP indeed meant it to be written using any general regex pattern, then my above code using comprehension will be needed. I can even write it as a function that can take the regex (like \d or even a complex one) as an argument and will dynamically generate a negative of passed regex and use that in the code. Let me know if this indeed is needed.


To me it sems that you just want the last position which matches a given pattern (in this case the not a number pattern).
This is as pythonic as it gets:

import re

string = 'uiae1iuae200'
pattern = r'[^0-9]'

match = re.match(fr'.*({pattern})', string)
print(match.end(1) - 1 if match else None)

Output:

8

 

Or the exact same as a function and with more test cases:

import re


def last_match(pattern, string):
    match = re.match(fr'.*({pattern})', string)
    return match.end(1) - 1 if match else None


cases = [(r'[^0-9]', 'uiae1iuae200'), (r'[^0-9]', '123a'), (r'[^0-9]', '123'), (r'[^abc]', 'abcabc1abc'), (r'[^1]', '11eea11')]

for pattern, string in cases:
    print(f'{pattern}, {string}: {last_match(pattern, string)}')

Output:

[^0-9], uiae1iuae200: 8
[^0-9], 123a: 3
[^0-9], 123: None
[^abc], abcabc1abc: 6
[^1], 11eea11: 4