Tilfeldig strenggenerering med store bokstaver og sifre

Jeg vil generere en streng av størrelse N.

Den skal bestå av tall og store engelske bokstaver som f.eks:

  • 6U1S75
  • 4Z4UKK
  • U911K4

Hvordan kan jeg oppnå dette på en pytonisk måte?

Løsning

Svar på én linje:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

eller enda kortere med Python 3.6 ved hjelp av random.choices():

''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

En kryptografisk sikrere versjon; se https://stackoverflow.com/a/23728630/2213647:

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

I detaljer, med en ren funksjon for videre gjenbruk:

>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
...    return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'

Hvordan fungerer det?

Vi importerer string, en modul som inneholder sekvenser av vanlige ASCII-tegn, og random, en modul som håndterer tilfeldig generering.

string.ascii_uppercase + string.digits sammenkjeder bare listen over tegn som representerer store ASCII-tegn og sifre:

>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

Deretter bruker vi en listeforståelse for å lage en liste med 'n' elementer:

>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']

I eksemplet ovenfor bruker vi [ for å opprette listen, men vi bruker ikke id_generator-funksjonen, slik at Python ikke oppretter listen i minnet, men genererer elementene på farten, ett etter ett (mer om dette her).

I stedet for å be om å opprette 'n' ganger strengen elem, vil vi be Python om å opprette 'n' ganger et tilfeldig tegn, plukket fra en sekvens av tegn:

>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'

Derfor random.choice(chars) for _ in range(size) skaper virkelig en sekvens av size tegn. Tegn som plukkes tilfeldig fra tegn:

>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']

Deretter kobler vi dem bare sammen med en tom streng slik at sekvensen blir en streng:

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Kommentarer (27)

En enklere, raskere, men litt mindre tilfeldig måte er å bruke random.sample i stedet for å velge hver bokstav for seg. Hvis n gjentakelser er tillatt, kan du utvide det tilfeldige grunnlaget med n ganger, f.eks.

import random
import string

char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))

Merk: random.sample forhindrer gjenbruk av tegn, ved å multiplisere størrelsen på tegnsettet blir flere gjentakelser mulig, men de er fortsatt mindre sannsynlige enn de er i et rent tilfeldig valg. Hvis vi går for en streng med lengde 6, og vi velger 'X' som det første tegnet, i valgeksemplet, er oddsen for å få 'X' for det andre tegnet det samme som oddsen for å få 'X' som det første tegnet. I random.sample-implementeringen er oddsen for å få 'X' som ethvert påfølgende tegn bare 6/7 sjansen for å få det som det første tegnet

Kommentarer (10)

Jeg trodde ingen hadde svart på dette ennå lol! Men hei, her er mitt eget forsøk:

import random

def random_alphanumeric(limit):
    #ascii alphabet of all alphanumerals
    r = (range(48, 58) + range(65, 91) + range(97, 123))
    random.shuffle(r)
    return reduce(lambda i, s: i + chr(s), r[:random.randint(0, len(r))], "")
Kommentarer (2)