Pythonic way to find the last position in a string not matching a regexIs there a way to run Python on Android?Finding the index of an item given a list containing it in PythonNicest way to pad zeroes to a stringPython join: why is it string.join(list) instead of list.join(string)?How to substring a string in Python?Getting the last element of a list in PythonReverse a string in PythonDoes Python have a string 'contains' substring method?How do I lowercase a string in Python?Most elegant way to check if the string is empty in Python?

Pulling the rope with one hand is as heavy as with two hands?

Why do Ichisongas hate elephants and hippos?

Any examples of headwear for races with animal ears?

Examples of non trivial equivalence relations , I mean equivalence relations without the expression " same ... as" in their definition?

Options leqno, reqno for documentclass or exist another option?

Will tsunami waves travel forever if there was no land?

Confused by notation of atomic number Z and mass number A on periodic table of elements

What word means to make something obsolete?

Was it really necessary for the Lunar Module to have 2 stages?

Where did the extra Pym particles come from in Endgame?

Stateful vs non-stateful app

Feels like I am getting dragged in office politics

Is it possible to measure lightning discharges as Nikola Tesla?

How to verbalise code in Mathematica?

Why the difference in metal between 銀行 and お金?

How does a Swashbuckler rogue "fight with two weapons while safely darting away"?

Python "triplet" dictionary?

Was there a Viking Exchange as well as a Columbian one?

Modify locally tikzset

Pressure to defend the relevance of one's area of mathematics

What's the metal clinking sound at the end of credits in Avengers: Endgame?

Is GOCE a satellite or aircraft?

Transfer over $10k

How to creep the reader out with what seems like a normal person?



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


Is there a way to run Python on Android?Finding the index of an item given a list containing it in PythonNicest way to pad zeroes to a stringPython join: why is it string.join(list) instead of list.join(string)?How to substring a string in Python?Getting the last element of a list in PythonReverse a string in PythonDoes Python have a string 'contains' substring method?How do I lowercase a string in Python?Most elegant way to check if the string is empty in Python?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








11















In Python, I try to find the last position in an arbitrary string that does not match a given pattern, which is specified as regex pattern (that includes the "not" in the match). For example, with the string uiae1iuae200, and the pattern of not being a number (regex pattern in Python for this would be [^0-9]), I would need '8' (the last 'e' before the '200') as result.




What is the most pythonic way to achieve this?




As it's a little tricky to quickly find method documentation and the best suited method for something in the Python docs (due to method docs being somewhere in the middle of the corresponding page, like re.search() in the re page), the best way I quickly found myself is using re.search() - but the current form simply must be a suboptimal way of doing it:



import re
string = 'uiae1iuae200' # the string to investigate
len(string) - re.search(r'[^0-9]', string[::-1]).start()


I am not satisfied with this for two reasons:
- a) I need to reverse string before using it with [::-1], and
- b) I also need to reverse the resulting position (subtracting it from len(string) because of having reversed the string before.



There needs to be better ways for this, likely even with the result of re.search().



I am aware of re.search(...).end() over .start(), but re.search() seems to split the results into groups, for which I did not quickly find a not-cumbersome way to apply it to the last matched group. Without specifying the group, .start(), .end(), etc, seem to always match the first group, which does not have the position information about the last match. However, selecting the group seems to at first require the return value to temporarily be saved in a variable (which prevents neat one-liners), as I would need to access both the information about selecting the last group and then to select .end() from this group.



What's your pythonic solution to this? I would value being pythonic more than having the most optimized runtime.



Update



The solution should be functional also in corner cases, like 123 (no position that matches the regex), empty string, etc. It should not crash e.g. because of selecting the last index of an empty list. However, as even my ugly answer above in the question would need more than one line for this, I guess a one-liner might be impossible for this (simply because one needs to check the return value of re.search() or re.finditer() before handling it). I'll accept pythonic multi-line solutions to this answer for this reason.










share|improve this question



















  • 1





    last position that does 'not' or does match regex? Last e matches [^0-9] pattern.

    – dgumo
    10 hours ago











  • Last position that does not match a certain pattern, like being a number. For numbers this would be [^0-9]. I'll update the question.

    – geekoverdose
    10 hours ago











  • Should s = 'uiae1iuae200aaaaaaaa' return the index of last char before a digit aka e (8) or the last char aka a (19)?

    – ruohola
    10 hours ago







  • 1





    With uiae1iuae200aaaaaaaa it should return the last position in the string, means 19.

    – geekoverdose
    10 hours ago












  • "way to find last position in string that does not match regex", you actually just want to find the last position that does match a given regex, in this case the regex just happens to be a negative character set.

    – ruohola
    5 hours ago

















11















In Python, I try to find the last position in an arbitrary string that does not match a given pattern, which is specified as regex pattern (that includes the "not" in the match). For example, with the string uiae1iuae200, and the pattern of not being a number (regex pattern in Python for this would be [^0-9]), I would need '8' (the last 'e' before the '200') as result.




What is the most pythonic way to achieve this?




As it's a little tricky to quickly find method documentation and the best suited method for something in the Python docs (due to method docs being somewhere in the middle of the corresponding page, like re.search() in the re page), the best way I quickly found myself is using re.search() - but the current form simply must be a suboptimal way of doing it:



import re
string = 'uiae1iuae200' # the string to investigate
len(string) - re.search(r'[^0-9]', string[::-1]).start()


I am not satisfied with this for two reasons:
- a) I need to reverse string before using it with [::-1], and
- b) I also need to reverse the resulting position (subtracting it from len(string) because of having reversed the string before.



There needs to be better ways for this, likely even with the result of re.search().



I am aware of re.search(...).end() over .start(), but re.search() seems to split the results into groups, for which I did not quickly find a not-cumbersome way to apply it to the last matched group. Without specifying the group, .start(), .end(), etc, seem to always match the first group, which does not have the position information about the last match. However, selecting the group seems to at first require the return value to temporarily be saved in a variable (which prevents neat one-liners), as I would need to access both the information about selecting the last group and then to select .end() from this group.



What's your pythonic solution to this? I would value being pythonic more than having the most optimized runtime.



Update



The solution should be functional also in corner cases, like 123 (no position that matches the regex), empty string, etc. It should not crash e.g. because of selecting the last index of an empty list. However, as even my ugly answer above in the question would need more than one line for this, I guess a one-liner might be impossible for this (simply because one needs to check the return value of re.search() or re.finditer() before handling it). I'll accept pythonic multi-line solutions to this answer for this reason.










share|improve this question



















  • 1





    last position that does 'not' or does match regex? Last e matches [^0-9] pattern.

    – dgumo
    10 hours ago











  • Last position that does not match a certain pattern, like being a number. For numbers this would be [^0-9]. I'll update the question.

    – geekoverdose
    10 hours ago











  • Should s = 'uiae1iuae200aaaaaaaa' return the index of last char before a digit aka e (8) or the last char aka a (19)?

    – ruohola
    10 hours ago







  • 1





    With uiae1iuae200aaaaaaaa it should return the last position in the string, means 19.

    – geekoverdose
    10 hours ago












  • "way to find last position in string that does not match regex", you actually just want to find the last position that does match a given regex, in this case the regex just happens to be a negative character set.

    – ruohola
    5 hours ago













11












11








11


1






In Python, I try to find the last position in an arbitrary string that does not match a given pattern, which is specified as regex pattern (that includes the "not" in the match). For example, with the string uiae1iuae200, and the pattern of not being a number (regex pattern in Python for this would be [^0-9]), I would need '8' (the last 'e' before the '200') as result.




What is the most pythonic way to achieve this?




As it's a little tricky to quickly find method documentation and the best suited method for something in the Python docs (due to method docs being somewhere in the middle of the corresponding page, like re.search() in the re page), the best way I quickly found myself is using re.search() - but the current form simply must be a suboptimal way of doing it:



import re
string = 'uiae1iuae200' # the string to investigate
len(string) - re.search(r'[^0-9]', string[::-1]).start()


I am not satisfied with this for two reasons:
- a) I need to reverse string before using it with [::-1], and
- b) I also need to reverse the resulting position (subtracting it from len(string) because of having reversed the string before.



There needs to be better ways for this, likely even with the result of re.search().



I am aware of re.search(...).end() over .start(), but re.search() seems to split the results into groups, for which I did not quickly find a not-cumbersome way to apply it to the last matched group. Without specifying the group, .start(), .end(), etc, seem to always match the first group, which does not have the position information about the last match. However, selecting the group seems to at first require the return value to temporarily be saved in a variable (which prevents neat one-liners), as I would need to access both the information about selecting the last group and then to select .end() from this group.



What's your pythonic solution to this? I would value being pythonic more than having the most optimized runtime.



Update



The solution should be functional also in corner cases, like 123 (no position that matches the regex), empty string, etc. It should not crash e.g. because of selecting the last index of an empty list. However, as even my ugly answer above in the question would need more than one line for this, I guess a one-liner might be impossible for this (simply because one needs to check the return value of re.search() or re.finditer() before handling it). I'll accept pythonic multi-line solutions to this answer for this reason.










share|improve this question
















In Python, I try to find the last position in an arbitrary string that does not match a given pattern, which is specified as regex pattern (that includes the "not" in the match). For example, with the string uiae1iuae200, and the pattern of not being a number (regex pattern in Python for this would be [^0-9]), I would need '8' (the last 'e' before the '200') as result.




What is the most pythonic way to achieve this?




As it's a little tricky to quickly find method documentation and the best suited method for something in the Python docs (due to method docs being somewhere in the middle of the corresponding page, like re.search() in the re page), the best way I quickly found myself is using re.search() - but the current form simply must be a suboptimal way of doing it:



import re
string = 'uiae1iuae200' # the string to investigate
len(string) - re.search(r'[^0-9]', string[::-1]).start()


I am not satisfied with this for two reasons:
- a) I need to reverse string before using it with [::-1], and
- b) I also need to reverse the resulting position (subtracting it from len(string) because of having reversed the string before.



There needs to be better ways for this, likely even with the result of re.search().



I am aware of re.search(...).end() over .start(), but re.search() seems to split the results into groups, for which I did not quickly find a not-cumbersome way to apply it to the last matched group. Without specifying the group, .start(), .end(), etc, seem to always match the first group, which does not have the position information about the last match. However, selecting the group seems to at first require the return value to temporarily be saved in a variable (which prevents neat one-liners), as I would need to access both the information about selecting the last group and then to select .end() from this group.



What's your pythonic solution to this? I would value being pythonic more than having the most optimized runtime.



Update



The solution should be functional also in corner cases, like 123 (no position that matches the regex), empty string, etc. It should not crash e.g. because of selecting the last index of an empty list. However, as even my ugly answer above in the question would need more than one line for this, I guess a one-liner might be impossible for this (simply because one needs to check the return value of re.search() or re.finditer() before handling it). I'll accept pythonic multi-line solutions to this answer for this reason.







python regex string regex-negation






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 hours ago









Emma

2,1543920




2,1543920










asked 11 hours ago









geekoverdosegeekoverdose

752616




752616







  • 1





    last position that does 'not' or does match regex? Last e matches [^0-9] pattern.

    – dgumo
    10 hours ago











  • Last position that does not match a certain pattern, like being a number. For numbers this would be [^0-9]. I'll update the question.

    – geekoverdose
    10 hours ago











  • Should s = 'uiae1iuae200aaaaaaaa' return the index of last char before a digit aka e (8) or the last char aka a (19)?

    – ruohola
    10 hours ago







  • 1





    With uiae1iuae200aaaaaaaa it should return the last position in the string, means 19.

    – geekoverdose
    10 hours ago












  • "way to find last position in string that does not match regex", you actually just want to find the last position that does match a given regex, in this case the regex just happens to be a negative character set.

    – ruohola
    5 hours ago












  • 1





    last position that does 'not' or does match regex? Last e matches [^0-9] pattern.

    – dgumo
    10 hours ago











  • Last position that does not match a certain pattern, like being a number. For numbers this would be [^0-9]. I'll update the question.

    – geekoverdose
    10 hours ago











  • Should s = 'uiae1iuae200aaaaaaaa' return the index of last char before a digit aka e (8) or the last char aka a (19)?

    – ruohola
    10 hours ago







  • 1





    With uiae1iuae200aaaaaaaa it should return the last position in the string, means 19.

    – geekoverdose
    10 hours ago












  • "way to find last position in string that does not match regex", you actually just want to find the last position that does match a given regex, in this case the regex just happens to be a negative character set.

    – ruohola
    5 hours ago







1




1





last position that does 'not' or does match regex? Last e matches [^0-9] pattern.

– dgumo
10 hours ago





last position that does 'not' or does match regex? Last e matches [^0-9] pattern.

– dgumo
10 hours ago













Last position that does not match a certain pattern, like being a number. For numbers this would be [^0-9]. I'll update the question.

– geekoverdose
10 hours ago





Last position that does not match a certain pattern, like being a number. For numbers this would be [^0-9]. I'll update the question.

– geekoverdose
10 hours ago













Should s = 'uiae1iuae200aaaaaaaa' return the index of last char before a digit aka e (8) or the last char aka a (19)?

– ruohola
10 hours ago






Should s = 'uiae1iuae200aaaaaaaa' return the index of last char before a digit aka e (8) or the last char aka a (19)?

– ruohola
10 hours ago





1




1





With uiae1iuae200aaaaaaaa it should return the last position in the string, means 19.

– geekoverdose
10 hours ago






With uiae1iuae200aaaaaaaa it should return the last position in the string, means 19.

– geekoverdose
10 hours ago














"way to find last position in string that does not match regex", you actually just want to find the last position that does match a given regex, in this case the regex just happens to be a negative character set.

– ruohola
5 hours ago





"way to find last position in string that does not match regex", you actually just want to find the last position that does match a given regex, in this case the regex just happens to be a negative character set.

– ruohola
5 hours ago












3 Answers
3






active

oldest

votes


















6














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:
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.






share|improve this answer




















  • 1





    Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

    – geekoverdose
    10 hours ago











  • @geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

    – ruohola
    1 hour ago


















2














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 will do the job quite nicely:



import re

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

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



Output:



8






share|improve this answer




















  • 1





    This goes towards what I am aiming for. Will test it when I have time!

    – geekoverdose
    10 hours ago











  • You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

    – Right leg
    8 hours ago











  • @geekoverdose Check my new answer :)

    – ruohola
    6 hours ago











  • @ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • @PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

    – ruohola
    1 hour ago


















0














This does not look Pythonic because it's not a one-liner, and it uses range(len(foo)), but it's pretty straightforward and probably not too inefficient.



def last_match(pattern, string):
for i in range(1, len(string) + 1):
substring = string[-i:]
if re.match(pattern, substring):
return len(string) - i


The idea is to iterate over the suffixes of string from the shortest to the longest, and to check if it matches pattern.



Since we're checking from the end, we know for sure that the first substring we meet that matches the pattern is the last.






share|improve this answer


















  • 2





    This is just not pythonic at all.

    – ruohola
    10 hours ago











  • I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

    – geekoverdose
    10 hours ago












  • @ruohola I'm interested to hear your criteria.

    – Right leg
    10 hours ago






  • 1





    This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

    – ruohola
    10 hours ago






  • 2





    I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

    – Julian Camilleri
    10 hours ago











Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55890245%2fpythonic-way-to-find-the-last-position-in-a-string-not-matching-a-regex%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









6














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:
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.






share|improve this answer




















  • 1





    Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

    – geekoverdose
    10 hours ago











  • @geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

    – ruohola
    1 hour ago















6














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:
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.






share|improve this answer




















  • 1





    Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

    – geekoverdose
    10 hours ago











  • @geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

    – ruohola
    1 hour ago













6












6








6







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:
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.






share|improve this answer















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:
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.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 hours ago

























answered 10 hours ago









Pushpesh Kumar RajwanshiPushpesh Kumar Rajwanshi

13.8k21331




13.8k21331







  • 1





    Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

    – geekoverdose
    10 hours ago











  • @geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

    – ruohola
    1 hour ago












  • 1





    Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

    – geekoverdose
    10 hours ago











  • @geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

    – ruohola
    1 hour ago







1




1





Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

– geekoverdose
10 hours ago





Upside: one-liner possible (move the [-1] one line up). Downside: list comprehension required. Still a very good take on my question I guess!

– geekoverdose
10 hours ago













@geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

– Pushpesh Kumar Rajwanshi
2 hours ago





@geekoverdose: If we have to do it using d as regex pattern, see my edited answer's last part to show, how it can be done much easily using just one call to re.match and get the index of last non-digit char without list comprehension or any such sort of thing.

– Pushpesh Kumar Rajwanshi
2 hours ago













I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

– ruohola
1 hour ago





I don't really see thought what kind of pattern can your list comprehension handle that the re.match can't?

– ruohola
1 hour ago













2














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 will do the job quite nicely:



import re

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

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



Output:



8






share|improve this answer




















  • 1





    This goes towards what I am aiming for. Will test it when I have time!

    – geekoverdose
    10 hours ago











  • You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

    – Right leg
    8 hours ago











  • @geekoverdose Check my new answer :)

    – ruohola
    6 hours ago











  • @ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • @PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

    – ruohola
    1 hour ago















2














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 will do the job quite nicely:



import re

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

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



Output:



8






share|improve this answer




















  • 1





    This goes towards what I am aiming for. Will test it when I have time!

    – geekoverdose
    10 hours ago











  • You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

    – Right leg
    8 hours ago











  • @geekoverdose Check my new answer :)

    – ruohola
    6 hours ago











  • @ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • @PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

    – ruohola
    1 hour ago













2












2








2







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 will do the job quite nicely:



import re

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

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



Output:



8






share|improve this answer















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 will do the job quite nicely:



import re

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

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



Output:



8







share|improve this answer














share|improve this answer



share|improve this answer








edited 1 hour ago

























answered 10 hours ago









ruoholaruohola

2,161425




2,161425







  • 1





    This goes towards what I am aiming for. Will test it when I have time!

    – geekoverdose
    10 hours ago











  • You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

    – Right leg
    8 hours ago











  • @geekoverdose Check my new answer :)

    – ruohola
    6 hours ago











  • @ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • @PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

    – ruohola
    1 hour ago












  • 1





    This goes towards what I am aiming for. Will test it when I have time!

    – geekoverdose
    10 hours ago











  • You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

    – Right leg
    8 hours ago











  • @geekoverdose Check my new answer :)

    – ruohola
    6 hours ago











  • @ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

    – Pushpesh Kumar Rajwanshi
    2 hours ago











  • @PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

    – ruohola
    1 hour ago







1




1





This goes towards what I am aiming for. Will test it when I have time!

– geekoverdose
10 hours ago





This goes towards what I am aiming for. Will test it when I have time!

– geekoverdose
10 hours ago













You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

– Right leg
8 hours ago





You defaced your original answer which was actually great. Now both your solutions uselessly clug the memory, and are no longer readable.

– Right leg
8 hours ago













@geekoverdose Check my new answer :)

– ruohola
6 hours ago





@geekoverdose Check my new answer :)

– ruohola
6 hours ago













@ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

– Pushpesh Kumar Rajwanshi
2 hours ago





@ruohola: Like I said earlier, OP used d just as an example as it was easy to demonstrate the example and in that case using list comprehension or something similar would be needed to store the multiple matches and their result. But if we really have to do it just for d as example, it can be done in a much easier way using a better regex. Check my edited answer to see how using a proper regex can avoid using list or list comprehension or any such thing in getting the index much easily, but this is only if d is the pattern.

– Pushpesh Kumar Rajwanshi
2 hours ago













@PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

– ruohola
1 hour ago





@PushpeshKumarRajwanshi Yeah, I +1 you, your solutions are really nice.

– ruohola
1 hour ago











0














This does not look Pythonic because it's not a one-liner, and it uses range(len(foo)), but it's pretty straightforward and probably not too inefficient.



def last_match(pattern, string):
for i in range(1, len(string) + 1):
substring = string[-i:]
if re.match(pattern, substring):
return len(string) - i


The idea is to iterate over the suffixes of string from the shortest to the longest, and to check if it matches pattern.



Since we're checking from the end, we know for sure that the first substring we meet that matches the pattern is the last.






share|improve this answer


















  • 2





    This is just not pythonic at all.

    – ruohola
    10 hours ago











  • I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

    – geekoverdose
    10 hours ago












  • @ruohola I'm interested to hear your criteria.

    – Right leg
    10 hours ago






  • 1





    This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

    – ruohola
    10 hours ago






  • 2





    I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

    – Julian Camilleri
    10 hours ago















0














This does not look Pythonic because it's not a one-liner, and it uses range(len(foo)), but it's pretty straightforward and probably not too inefficient.



def last_match(pattern, string):
for i in range(1, len(string) + 1):
substring = string[-i:]
if re.match(pattern, substring):
return len(string) - i


The idea is to iterate over the suffixes of string from the shortest to the longest, and to check if it matches pattern.



Since we're checking from the end, we know for sure that the first substring we meet that matches the pattern is the last.






share|improve this answer


















  • 2





    This is just not pythonic at all.

    – ruohola
    10 hours ago











  • I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

    – geekoverdose
    10 hours ago












  • @ruohola I'm interested to hear your criteria.

    – Right leg
    10 hours ago






  • 1





    This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

    – ruohola
    10 hours ago






  • 2





    I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

    – Julian Camilleri
    10 hours ago













0












0








0







This does not look Pythonic because it's not a one-liner, and it uses range(len(foo)), but it's pretty straightforward and probably not too inefficient.



def last_match(pattern, string):
for i in range(1, len(string) + 1):
substring = string[-i:]
if re.match(pattern, substring):
return len(string) - i


The idea is to iterate over the suffixes of string from the shortest to the longest, and to check if it matches pattern.



Since we're checking from the end, we know for sure that the first substring we meet that matches the pattern is the last.






share|improve this answer













This does not look Pythonic because it's not a one-liner, and it uses range(len(foo)), but it's pretty straightforward and probably not too inefficient.



def last_match(pattern, string):
for i in range(1, len(string) + 1):
substring = string[-i:]
if re.match(pattern, substring):
return len(string) - i


The idea is to iterate over the suffixes of string from the shortest to the longest, and to check if it matches pattern.



Since we're checking from the end, we know for sure that the first substring we meet that matches the pattern is the last.







share|improve this answer












share|improve this answer



share|improve this answer










answered 10 hours ago









Right legRight leg

8,70342450




8,70342450







  • 2





    This is just not pythonic at all.

    – ruohola
    10 hours ago











  • I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

    – geekoverdose
    10 hours ago












  • @ruohola I'm interested to hear your criteria.

    – Right leg
    10 hours ago






  • 1





    This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

    – ruohola
    10 hours ago






  • 2





    I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

    – Julian Camilleri
    10 hours ago












  • 2





    This is just not pythonic at all.

    – ruohola
    10 hours ago











  • I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

    – geekoverdose
    10 hours ago












  • @ruohola I'm interested to hear your criteria.

    – Right leg
    10 hours ago






  • 1





    This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

    – ruohola
    10 hours ago






  • 2





    I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

    – Julian Camilleri
    10 hours ago







2




2





This is just not pythonic at all.

– ruohola
10 hours ago





This is just not pythonic at all.

– ruohola
10 hours ago













I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

– geekoverdose
10 hours ago






I've come up with something similar to this, but I am not satisfied with its structure. A pythonic one-liner that is easily understand- and maintainable would be preferred. If this really is one of the most pythonic ways to achieve my goal, then I feel like filing a bug report with Python for this.

– geekoverdose
10 hours ago














@ruohola I'm interested to hear your criteria.

– Right leg
10 hours ago





@ruohola I'm interested to hear your criteria.

– Right leg
10 hours ago




1




1





This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

– ruohola
10 hours ago





This is not very readable, uses the range(len(foo)) antipattern, is quite a lot of lines etc. It's a valid solution, but when OP asked specifically for a 'pythonic' solution, I don't feel like this cuts it.

– ruohola
10 hours ago




2




2





I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

– Julian Camilleri
10 hours ago





I think you guys are confusing what pythonic is. Zen of python: "Readability counts." A crunched one liner doesn't mean its pythonic.

– Julian Camilleri
10 hours ago

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55890245%2fpythonic-way-to-find-the-last-position-in-a-string-not-matching-a-regex%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Can not update quote_id field of “quote_item” table magento 2Magento 2.1 - We can't remove the item. (Shopping Cart doesnt allow us to remove items before becomes empty)Add value for custom quote item attribute using REST apiREST API endpoint v1/carts/cartId/items always returns error messageCorrect way to save entries to databaseHow to remove all associated quote objects of a customer completelyMagento 2 - Save value from custom input field to quote_itemGet quote_item data using quote id and product id filter in Magento 2How to set additional data to quote_item table from controller in Magento 2?What is the purpose of additional_data column in quote_item table in magento2Set Custom Price to Quote item magento2 from controller

Magento 2 disable Secret Key on URL's from terminal The Next CEO of Stack OverflowMagento 2 Shortcut/GUI tool to perform commandline tasks for windowsIn menu add configuration linkMagento oAuth : Generating access token and access secretMagento 2 security key issue in Third-Party API redirect URIPublic actions in admin controllersHow to Disable Cache in Custom WidgetURL Key not changing in Magento 2Product URL Key gets deleted when importing custom options - Magento 2Problem with reindex terminalMagento 2 - bin/magento Commands not working in Cpanel Terminal

Create Account not working properly for Guest User : Delete operation is forbidden for current area (Enterprise Magento ver. 2.1.0)Delete operation is forbidden for current areaUnrelated attribute error The value of attribute “unrelated” must be setDelete operation is forbidden for current area error when creating account from checkout success page“Delete operation is forbidden for current area” error while create customer in Magento 2Magento 2. Custom Attribute And Plugin in ModuleM2: Can't register user when set register form to show address fields. Error Delete operation is forbidden for current areaHow to update custom shipping address attribute value after order placeDelete operation is forbidden for current area magento 2Set custom value from query result for product attribute in magento 2 admin panelhow to Placed order as another customer in Magento 2 checkout