How to increment string like a number?
Question:
Given the charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", how can I increment a string like following:
aabbcde -> aabbcdf -> aabbcdg -> … -> aabbcd0 -> aabbcea
I would like a snippet in Python.
Thank you!
Answers:
you can use a for loop like this:
for character in charset:
print("aabbc" + character)
and then modify it so that after all combinations with "d" it prints "e" and then iterates through charset again.
We have 62 digits:
>>> DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
>>> len(DIGITS)
62
so the easiest way to tackle the problem IMO is to implement a base-62 representation using those digits, since str->int conversion with a given set of digit characters is a well-trodden path (you can google up a quick reference implementation to base your conversion functions on if it’s one you haven’t trodden personally before):
>>> def from_b62(num: str) -> int:
... if num.startswith("-"):
... return -from_b62(num[1:])
... return sum(DIGITS.index(d) * 62 ** i for i, d in enumerate(num[::-1]))
...
>>> def to_b62(num: int) -> str:
... if num < 0:
... return "-" + to_b62(-num)
... d = ""
... while num:
... d = DIGITS[num % 62] + d
... num //= 62
... return d or DIGITS[0]
...
Now we can convert a string to an int in our base-62 system, add 1, and convert it back:
>>> from_b62("aabbcde") + 1
15022543
>>> to_b62(15022543)
'bbcdf'
Note that to_b62
doesn’t preserve the leading a
s (which are zeroes) from the original string, since they aren’t part of the numeric value, but if you put the two operations into a single function you can rjust
the result to the length of the original string:
>>> def inc_b62(num: str, step=1) -> str:
... return to_b62(from_b62(num) + step).rjust(len(num), DIGITS[0])
...
>>> inc_b62("aabbcde")
'aabbcdf'
>>> inc_b62("aabbcdf")
'aabbcdg'
>>> inc_b62("aabbcd0")
'aabbcea'
This returns exactly like your example:
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
my_string = "aabbcd0"
def incriment_str(string: str, last_char_i=None):
if last_char_i is None:
last_char_i = (len(string)) - 1
last_char = string[last_char_i]
last_char_map_i = charset.find(last_char)
if last_char_map_i == len(charset) - 1 :
next_char = charset[0]
return incriment_str(my_string[:last_char_i], last_char_i - 1) + next_char
else:
next_char = charset[last_char_map_i + 1]
return my_string[:last_char_i] + next_char
# Testing
print(my_string)
for i in range(100000000000):
my_string = incriment_str(my_string)
print(my_string)
Given the charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", how can I increment a string like following:
aabbcde -> aabbcdf -> aabbcdg -> … -> aabbcd0 -> aabbcea
I would like a snippet in Python.
Thank you!
you can use a for loop like this:
for character in charset:
print("aabbc" + character)
and then modify it so that after all combinations with "d" it prints "e" and then iterates through charset again.
We have 62 digits:
>>> DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
>>> len(DIGITS)
62
so the easiest way to tackle the problem IMO is to implement a base-62 representation using those digits, since str->int conversion with a given set of digit characters is a well-trodden path (you can google up a quick reference implementation to base your conversion functions on if it’s one you haven’t trodden personally before):
>>> def from_b62(num: str) -> int:
... if num.startswith("-"):
... return -from_b62(num[1:])
... return sum(DIGITS.index(d) * 62 ** i for i, d in enumerate(num[::-1]))
...
>>> def to_b62(num: int) -> str:
... if num < 0:
... return "-" + to_b62(-num)
... d = ""
... while num:
... d = DIGITS[num % 62] + d
... num //= 62
... return d or DIGITS[0]
...
Now we can convert a string to an int in our base-62 system, add 1, and convert it back:
>>> from_b62("aabbcde") + 1
15022543
>>> to_b62(15022543)
'bbcdf'
Note that to_b62
doesn’t preserve the leading a
s (which are zeroes) from the original string, since they aren’t part of the numeric value, but if you put the two operations into a single function you can rjust
the result to the length of the original string:
>>> def inc_b62(num: str, step=1) -> str:
... return to_b62(from_b62(num) + step).rjust(len(num), DIGITS[0])
...
>>> inc_b62("aabbcde")
'aabbcdf'
>>> inc_b62("aabbcdf")
'aabbcdg'
>>> inc_b62("aabbcd0")
'aabbcea'
This returns exactly like your example:
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
my_string = "aabbcd0"
def incriment_str(string: str, last_char_i=None):
if last_char_i is None:
last_char_i = (len(string)) - 1
last_char = string[last_char_i]
last_char_map_i = charset.find(last_char)
if last_char_map_i == len(charset) - 1 :
next_char = charset[0]
return incriment_str(my_string[:last_char_i], last_char_i - 1) + next_char
else:
next_char = charset[last_char_map_i + 1]
return my_string[:last_char_i] + next_char
# Testing
print(my_string)
for i in range(100000000000):
my_string = incriment_str(my_string)
print(my_string)