0

So using the code i have when generating a number/letter string it generates an extra dash on the end and i want it to only consist of 16 digits numbers and letters (without the extra dash)

import string, random

def generateCode():
    code = ''
    for i in xrange(16):
        number = random.choice(string.ascii_letters + string.digits)
        code += str(number)
        if (i - 3) % 4 == 0 and i - 4:
            code += '-'

    file = open('AlphaKeys.txt', 'w')
    file.write(code + '\n')
    file.close()
    return code

generateCode()

And an example of the output: qIss-wXbS-PZo7-audg-

cs95
  • 379,657
  • 97
  • 704
  • 746
legacy
  • 13
  • 5

4 Answers4

0

The second condition in your if statement serves no meaningful purpose. You should just modify it so as to not add the - if you're at the last iteration:

if (i - 3) % 4 == 0 and i < 15:
    ...

Making this change gives me:

LjIs-6HT5-zZMD-HMMz

Might I suggest an improvement over your current approach with random.sample?

import random

r = string.ascii_letters + string.digits
string =  '-'.join(''.join(random.sample(r, 4)) for _ in range(4))
print(string)

'fiqc-fvbc-z7s9-62w3'

Note that random.sample does not offer replacement per call, so if you want that, you'll need random.choice.

If you want randomness with replacement, you can substitute random.sample with random.choices - but only from python3.6 and onwards.

cs95
  • 379,657
  • 97
  • 704
  • 746
0

Of course, you're adding the dash even at the last iteration.

Anyway, the most pythonic way: just nest 2 str.join statements:

import string,random

code = "-".join(["".join([random.choice(string.ascii_letters + string.digits) for _ in range(4)]) for _ in range(4)])

print(code)

an example:

m7b1-A0vS-JARQ-hlo2

the inner comprension generates the 4 letter/digit sequence, and the outer one joins 4 of those sequences with -.

Note that the join([..]) syntax may appear cumbersome, but is faster than without the square brackets (Joining strings. Generator or list comprehension?)

EDIT: note that your digits/letters can repeat with random.choice. A better approach without repeats would be to use random.choice as follows:

import string,random

it = iter(random.sample(string.ascii_letters + string.digits,16))

code = "".join(["-" if i % 5 == 4 else next(it) for i in range(19)])

the iterator is consumed except when it's time to issue a dash.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
0

Yet another alternative, with only one loop :

import string,random
possible_chars = string.ascii_letters + string.digits
"".join(random.choice(possible_chars) if i % 5 < 4 else '-' for i in range(19))
#=> '4Mhg-flw1-lUEu-pu3h'
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
0

Another way would be to add the code that adds the dash before adding the number. eg.

if i and i % 4 == 0:
     code+= '-'
number = random.choice(string.ascii_letters + string.digits)
code += str(number)

which is a bit more readable than doing it after with

if (i - 3) % 4 == 0 and i < 15: code+= '-'

but in general using join would be the more pythonic way eg.

def code_part():
    return ''.join(random.choice(string.ascii_letters + string.digits) 
                   for i in xrange(4))
'-'.join(code_part() for i in xrange(4))
meili
  • 191
  • 5