4

I am creating a passkey of 16 alphanumeric characters where I am generating starting 4 digits with A001, A002, A003 till A999. Once it goes till A999, the alphabet will auto increase to B and digits will again start with 001. And the same process will go till Z999. Once the A-Z series will over, then it will start with AA01 and so on. How to do this thing in python? As I am new in python so I tried it on my own and also tried some examples but I am unable to make the increment of characters. Any ideas or thoughts would be greatly appreciated.

Many thanks

rec=0
new_list16 = []
def autoIncrement():
    global rec
    first = 'A'
    i = chr(ord(first))
    new_list16.append(i)

    while True:
        pStart = 1 #adjust start value, if req'd 
        pInterval = 1 #adjust interval value, if req'd
        if (rec == 0):
            rec += pStart
        else:
            rec = rec + pInterval
        return str(rec).zfill(3)
#print(autoIncrement())
new_list16.append(autoIncrement())

print(*new_list16, sep = '')
rajat maan
  • 171
  • 11
  • Use [this](https://stackoverflow.com/questions/181596/how-to-convert-a-column-number-eg-127-into-an-excel-column-eg-aa) for the A-Z part; the 001 part is just the number modulo 1000. – tobias_k Feb 03 '20 at 12:51
  • 1
    Going from A999 to B001 instead of B000 really messes things up... – tobias_k Feb 03 '20 at 13:45

5 Answers5

2

Going from A999 to B001 instead of B000 really messes things up a bit, but you can still use this for the A-Z part, and a simple modulo operation for the numbers.

def excel_format(num):
    # see https://stackoverflow.com/a/182924/1639625
    res = ""
    while num:
        mod = (num - 1) % 26
        res = chr(65 + mod) + res
        num = (num - mod) // 26
    return res

def full_format(num, d=3):
    chars = num // (10**d-1) + 1 # this becomes   A..ZZZ
    digit = num %  (10**d-1) + 1 # this becomes 001..999
    return excel_format(chars) + "{:0{}d}".format(digit, d)

for i in range(10000):
    print(i, full_format(i, d=2))

Number of digits in the numeric part is controlled with the optional d parameter. I'll use 2 for purpose of demonstration, but 3 works just as well.

0 A01
...
98 A99
99 B01
...
2573 Z99
2574 AA01
...
9998 CW99
9999 CX01
tobias_k
  • 81,265
  • 12
  • 120
  • 179
1

This probably needs to be tested and refactored more, but here's a start for you:

def leadingZeros(number, digits):
    numberString = str(number)
    for digit in range(1, digits):
        if number < 10**digit:
            numberString = '0' + numberString
    return numberString


def autoIncrement(oldNumber):
    order = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!'
    lastDigitOrder = order.find(oldNumber[3])
    newNumber = ''
    if order.find(oldNumber[1]) <= 9:
        # 3 digit number
        number = int(oldNumber[1:]) + 1
        letter = oldNumber[0]
        if 1000 == number:
            letterOrder = order.find(oldNumber[0])
            letter = order[letterOrder + 1]
        newNumber = letter + leadingZeros(number % 1000, 3)
    elif order.find(oldNumber[2]) <= 9:
        # 2 digit number
        number = int(oldNumber[2:]) + 1
        letters = oldNumber[0:2]
        if 100 == number:
            letterOrder = order.find(oldNumber[1])
            letter = order[letterOrder + 1]
            letters = oldNumber[0] + letter
        newNumber = letters + leadingZeros(number % 100, 2)
    elif order.find(oldNumber[3]) <= 9:
        # 1 digit number
        number = int(oldNumber[3]) + 1
        letters = oldNumber[0:3]
        if 10 == number:
            letterOrder = order.find(oldNumber[2])
            letter = order[letterOrder + 1]
            letters = oldNumber[0:2] + letter
        newNumber = letters + leadingZeros(number % 10, 1)
    else:
        # just letters
        print(oldNumber)
        letterOrder = order.find(oldNumber[3])
        letter = order[letterOrder + 1]
        newNumber = oldNumber[0:3] + letter

    # if one of the digits has gone past Z then we need to update the letters
    if '!' == newNumber[3]:
        # past Z in 4th digit
        letterOrder = order.find(oldNumber[2])
        newNumber = newNumber[0:2] + order[letterOrder + 1] + 'A'
    if '!' == newNumber[2]:
        # past Z in 3rd digit
        letterOrder = order.find(oldNumber[1])
        newNumber = newNumber[0:1] + order[letterOrder + 1] + 'A' + newNumber[3]
    if '!' == newNumber[1]:
        # past Z in 2nd digit
        letterOrder = order.find(oldNumber[0])
        newNumber = order[letterOrder + 1] + 'A' + newNumber[2:]

    return newNumber


print(autoIncrement('A999'))
print(autoIncrement('AA99'))
print(autoIncrement('AAA9'))
print(autoIncrement('AAAA'))
print(autoIncrement('AZZ9'))
wogsland
  • 9,106
  • 19
  • 57
  • 93
1

This is not quite what you are asking for, but if your requirement is for 4-character "sequential" strings, let me suggest a far more simpler approach. Why not simply used base 36 numbers? That is, have your numbers go from 0, 1, 2, ... A, B, C, ... Z, 10, 11, 12, ... 1Z, ... Then to convert one of the base 36 strings to an int it is simply:

n = int('12AV', 36)

And to convert an int to a base n string:

def baseN(num, base, numerals="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
      return ((num == 0) and numerals[0]) or (baseN(num // base, base, numerals).lstrip(numerals[0]) + numerals[num % base])

Putting it all together:

n = int('12AV', 36)
s = baseN(n + 1, 36)
print(s)

Prints:

12AW

You can, of course, start with 'A001' if you need to. You will then go to A00Z after 35 iterations. You will end up generating the same numbers as in your original method, just in a different order.

Booboo
  • 38,656
  • 3
  • 37
  • 60
1
def auto_increment(number):
    if number == 'ZZZZ':
        return 'ZZZZ'

    digits = "".join([i for i in number if i.isdigit()])
    chars = "".join([i for i in number if not i.isdigit()])
    if int(digits) == int('9' * len(digits)):
        digits = "000"
        new_char = [ord(i) for i in chars]
        if new_char[-1] % ord('Z') == 0:
            new_char = "".join([chr(i) for i in new_char]) + 'A'
        else:
            new_char[-1] = new_char[-1] + 1
            new_char = "".join([chr(i) for i in new_char])
    else:
        new_char = chars

    new_digit = int(digits) + 1
    l = len(new_char) 
    ll = len(str(new_digit))
    new_digit = (("0" * (3-ll)) + str(new_digit))[(l-1):]
    return f"{new_char}{new_digit}"

This function return you the next number, given any number. for example: A999 will return AB01.

you can now just use this function in a loop.

Awaish Kumar
  • 537
  • 6
  • 22
  • Sir, it also works fine.But the problem is that after Z999, the digits should remain same, but it varies to 5 digits. – rajat maan Feb 11 '20 at 05:30
  • And could i do it with using functions because this passkey work is included in a running function.? – rajat maan Feb 11 '20 at 07:35
  • after Z999, it should go to ZA01 because we are using letters after digits.and it is working perfectly. It never goes to 5 digits, have you even tried running it? Also can you also select it as correct answer. – Awaish Kumar Feb 12 '20 at 09:30
0

Thank you for the solutions you had provided. But I tried something exactly which I want for my question. Please check it and give your comments on it.

def full_format(i):
    # limit of first range is 26 letters (A-Z) times 999 numbers (001-999)
    if i < 26 * 999:
        c,n = divmod(i,999)   # quotient c is index of letter 0-25, remainder n is 0-998
        c = chr(ord('A') + c) # compute letter
        n += 1
        return f'{c}{n:03}'
    # After first range, second range is 26 letters times 26 letters * 99 numbers (01-99)
    elif i < 26*999 + 26*26*99:
        i -= 26*999               # remove first range offset
        cc,n = divmod(i,99)       # remainder n is 0-98, use quotient cc to compute two letters
        c1,c2 = divmod(cc,26)     # c1 is index of first letter, c2 is index of second letter
        c1 = chr(ord('A') + c1)   # compute first letter
        c2 = chr(ord('A') + c2)   # compute second letter
        n += 1
        return f'{c1}{c2}{n:02}'
    else:
        raise OverflowError(f'limit is {26*999+26*26*99}')

for i in range(92880, 92898):
    print(full_format(i))
rajat maan
  • 171
  • 11