2

I'd like to increment the last digit of user provided string in Python 2.7.

I can replace the first digit like this:

def increment_hostname(name):
    try:
        number = re.search(r'\d+', name).group() 
    except AttributeError:
        return False            
    number = int(number) + 1
    number = str(number)
    return re.sub(r'\d+', number, name)       

I can match all the digits with re.findall then increment the last digit in the list but I'm not sure how to do the replace:

number = re.findall(r'\d+', name)     
number = numbers[-1]
number = int(number) + 1                      
number = str(number)
Merch
  • 63
  • 3
  • 8

1 Answers1

10

Use negative look ahead to see that there are no digits after a digit, pass a function to the re.sub() replacement argument and increment the digit in it:

>>> import re
>>> s = "foo 123 bar"
>>> re.sub('\d(?!\d)', lambda x: str(int(x.group(0)) + 1), s)
'foo 124 bar'

You may also want to handle 9 in a special way, for example, replace it with 0:

>>> def repl(match):
...     digit = int(match.group(0))
...     return str(digit + 1 if digit != 9 else 0)
... 
>>> s = "foo 789 bar"
>>> re.sub('\d(?!\d)', repl, s)
'foo 780 bar'

UPD (handling the new example):

>>> import re
>>> s = "f.bar-29.domain.com"
>>> re.sub('(\d+)(?!\d)', lambda x: str(int(x.group(0)) + 1), s)
'f.bar-30.domain.com'
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • If there are two sets of numbers this will increment both of them. Sorry if I wasn't clear in my question but I want to be able handle names such as foo1.bar-2.domain.com and increment the 2. In cases with one set of number I don't have to limit the substitution to the last digit so f.bar-29.domain.com could become foo.bar-30.domain.com. Thanks for the tip about negative look ahead that is very helpful. – Merch May 23 '14 at 17:07
  • @Merch good, check the `UPD` section - I've slightly modified the regex to handle the case. – alecxe May 23 '14 at 20:08
  • 2
    @alecxe For your UPD, if you want to increment ONLY the last number, you need (\d+)(?!.*\d) as found in http://stackoverflow.com/a/5320864/3571110. Your regex will increment all numbers found. So f.3bar-29.domain.com would become f.4bar-30.domain.com with (\d+)(?!\d) and f.3bar-30.domain.com with (\d+)(?!.*\d) – proximous Nov 02 '15 at 21:00
  • @proximous thanks for sharing that worked perfectly for my needs. Saved me alot of trouble with bumping just last digit in varying digit group lenths including ones with letters. ``` last_tag = 'v2.6.32.27' new_tag = re.sub(r"(\d+)(?!.*\d)", lambda x: str(int(x.group(0)) + 1), last_tag) ``` Results in: v2.6.32.28 – Mike R Dec 02 '21 at 16:56