Examples:
Some regexes that I have tried:
import re
m = re.search(r"(\d).*?\1", string)
print(m.group(1))
import re
m = re.search(r"(\d)(?!(\d).*?\2).*?\1", string)
print(m.group(1))
Regex may not be the right tool for the task. While the regex in @CasimiretHippolyte's answer works, it is rather inefficient having to scan the entire rest of the string for each character in the string until a matching character is found, costing an average time complexity of O(n ^ 2).
A more efficient approach with a linear time complexity would be to use a set to keep track of characters that have been encountered, and return the first character already added to the set:
def first_repeating_digit(string):
seen = set()
for digit in filter(str.isdigit, string):
if digit in seen:
return digit
seen.add(digit)
raise ValueError('No repeating digit found.')
so that:
for s in '0123123123', '01234554321':
print(s, first_repeating_digit(s))
outputs:
0123123123 1
01234554321 5
Demo here
Benchmark test result:
blhsing 0123123123 1.2911038296297193
blhsing 01234554321 1.3835312821902335
CasimiretHippolyte 0123123123 3.6279739402234554
CasimiretHippolyte 01234554321 4.1985282939858735
One idea: capture the end of the string and add it in the negative lookahead (group 2 here):
(\d)(?=.*?\1(.*))(?!.*?(\d).*?\3.+?\2$)
This way you can control where the subpattern .*?(\d).*?\3 in the negative lookahead ends. If .+?\2$ succeeds, that means there's an other digit that is repeated before the one in group 1.
I anchored the pattern for the regex101 demo with ^.*?, but you don't need to do that with the re.search method.
Other way: reverse the string and find the last repeated digit:
re.search(r'^.*(\d).*?\1', string[::-1]).group(1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With