Adding characters adding one character in front

what I'm trying to implement is a function that increments a string by one character, for example:

'AAA' + 1 = 'AAB' 'AAZ' + 1 = 'ABA' 'ZZZ' + 1 = 'AAAA' 

I implemented a function for the first two cases, however, I cannot come up with any solution for the third case.

Here is my code:

 def new_sku(s): s = s[::-1] already_added = False new_sku = str() for i in s: if not already_added: if (i < 'Z'): already_added = True new_sku += chr((ord(i)+1)%65%26 + 65) else: new_sku += i return new_sku[::-1] 

Any suggestions?

+6
source share
10 answers

What about?

 def new_sku(s): s = s[::-1] already_added = False new_sku = str() for i in s: if not already_added: if (i < 'Z'): already_added = True new_sku += chr((ord(i)+1)%65%26 + 65) else: new_sku += i if not already_added: # carry still left? new_sku += 'A' return new_sku[::-1] 

Run Example: -

 $ python sku.py Z AA $ python sku.py ZZZ AAAA $ python sku.py AAA AAB $ python sku.py AAZ ABA 
+3
source

If you are dealing with bijective numbering , then you probably have (or should have) functions to convert to / from the bijective representation; it will be much easier, just convert to an integer, increment it, and then convert back:

 def from_bijective(s, digits=string.ascii_uppercase): return sum(len(digits) ** i * (digits.index(c) + 1) for i, c in enumerate(reversed(s))) def to_bijective(n, digits=string.ascii_uppercase): result = [] while n > 0: n, mod = divmod(n - 1, len(digits)) result += digits[mod] return ''.join(reversed(result)) def new_sku(s): return to_bijective(from_bijective(s) + 1) 
+9
source

You should think of "AAA", "ZZZ", ... as a representation of the value you are manipulating.

First, let's analyze the value:

 val = sum(pow(26, i) * (ord(v) - ord('A') + 1) for i, v in enumerate(value[::-1])) 

Then add the value to it:

 val = val + 1 

Edit

The final value is set:

 res = "" while val > 0: val, n = divmod(val - 1, 26) res = chr(n+ord('A')) + res 

The lack of a representation for zero requires that the value passed to divmod decrease on each turn, which I did not find a way to do with understanding the list.

Edit

Instead of ord() and chr() you can use string.ascii_uppercase.index() and string.ascii_uppercase[]

+3
source

Here you can use some recursion:

 def new_sku(s): s = s[::-1] new_s = '' return expand(s.upper(), new_s)[::-1] import string chars = string.ascii_uppercase def expand(s, new_s, carry_forward=True): if not s: new_s += 'A' if carry_forward else '' return new_s new_s += chars[(ord(s[0]) - ord('A') + carry_forward) % 26] # Slice the first character, and expand rest of the string if s[0] == 'Z': return expand(s[1:], new_s, carry_forward) else: return expand(s[1:], new_s, False) print new_sku('AAB') print new_sku('AAZ') print new_sku('ZZZ') print new_sku('aab') print new_sku('aaz') print new_sku('zzz') 

Output:

 AAC ABA AAAA AAC ABA AAAA 
+2
source

I would implement this as a base-26 add-on with a carry.

So, start on the right side of the line, add 1. If it reaches Z, wrap in and put the next character on the left one by one. If the leftmost character reaches Z, add A to the left of the line.

 s = ["Z","Z","Z"] done = 0 index = len(s) - 1 while done == 0: if s[index] < "Z": s[index] = chr(ord(s[index]) + 1) done = 1 else: s[index] = "A" if index == 0: s = ["A"] + s done = 1 else: index = index - 1 print s 
+1
source

Just check if there is a string Z s, and if it is, replace it with a string of length len(s) + 1 , consisting only of A s:

 if s == "Z" * len(s): return "A" * (len(s) + 1) 
+1
source
 alp='ABCDEFGHIJKLMNOPQRSTUVWXYZA' def rec(s): if len(s)==0:return 'A' last_letter=s[-1] if last_letter=='Z':return rec(s[:-1])+'A' return s[:-1]+alp[(alp.find(last_letter)+1)] 

result

 >>> rec('AAA') 'AAB' >>> rec('AAZ') 'ABA' >>> rec('ZZZ') 'AAAA' >>> rec('AZA') 'AZB' 
+1
source

How about this? As an easy way to handle a long line, you can add a leading “@” and split it if it has not been enlarged:

 >>> def new_sku(s): def increment(s): if s.endswith('Z'): return increment(s[:-1])+'A' else: return s[:-1]+chr(ord(s[-1])+1) t = increment('@'+s) return t.lstrip('@') >>> new_sku('AAA') 'AAB' >>> new_sku('AAZ') 'ABA' >>> new_sku('ZZZ') 'AAAA' 

If recursion bothers you, you can smooth it out like you already did, but still use the @ symbol, added and stripped.

+1
source

You can use the for-else loop:

 from string import ascii_uppercase as au def solve(strs): lis = [] for i, c in enumerate(strs[::-1], 1): ind = au.index(c) + 2 lis.append(au[(ind%26)-1]) if ind <= 26: break else: # This will execute only if the for-loop didn't break. lis.append('A') return strs[:-1*i] + "".join(lis[::-1]) print solve('AAA') print solve('AAZ') print solve('ZZZ') print solve('AZZZ') print solve('ZYZZ') print solve('ZYYZZ') 

output:

 AAB ABA AAAA BAAA ZZAA ZYZAA 
0
source

We can see that there are 3 conditions completely, you can iterate over a string and process one of the conditions. You can use string.ascii_uppercase instead of chr and ord

 import string def add(s): s = list(s)[::-1] for index, char in enumerate(s): if char != "Z": s[index] = string.ascii_uppercase[string.ascii_uppercase.index(char) + 1] return s[::-1] elif char == "Z" and (index != len(s) - 1): s[index] = "A" elif char == "Z" and (index == len(s) - 1): s[index] = "A" return ["A"] + s[::-1] 
0
source

Source: https://habr.com/ru/post/950699/


All Articles