Willekeurige tekenreeksen met hoofdletters en cijfers

Ik wil een string genereren van grootte N.

Het moet bestaan uit cijfers en Engelse hoofdletters, zoals:

  • 6U1S75
  • 4Z4UKK
  • U911K4

Hoe kan ik dit op een pythonische manier bereiken?

Oplossing

**Antwoord op één regel.

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

of zelfs korter vanaf Python 3.6 met behulp van random.choices():

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

Een cryptografisch veiliger versie; zie https://stackoverflow.com/a/23728630/2213647:

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

In detail, met een schone functie voor verder hergebruik:

>>> 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'

Hoe werkt het ?

We importeren string, een module die sequenties van gewone ASCII karakters bevat, en random, een module die zich bezighoudt met willekeurige generatie.

string.ascii_uppercase + string.digits voegt gewoon de lijst van tekens samen die hoofdletters en cijfers in ASCII voorstellen:

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

Dan gebruiken we een list comprehension om een lijst van 'n' elementen te maken:

>>> 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']

In het bovenstaande voorbeeld gebruiken we [ om de lijst te maken, maar dat doen we niet in de id_generator functie, zodat Python de lijst niet in het geheugen maakt, maar de elementen één voor één genereert (meer hierover hier).

In plaats van te vragen om 'n' keer de string elem aan te maken, zullen we Python vragen om 'n' keer een willekeurig karakter aan te maken, gekozen uit een reeks karakters:

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

Daarom is random.choice(chars) for _ in range(size) echt het creëren van een reeks size karakters. Tekens die willekeurig worden gekozen uit chars:

>>> [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']

Dan voegen we ze samen met een lege string, zodat de reeks een string wordt:

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

Een eenvoudigere, snellere maar iets minder willekeurige manier is om random.sample te gebruiken in plaats van elke letter apart te kiezen, Als n-herhalingen zijn toegestaan, vergroot dan je willekeurige basis met n keer, bijv.

import random
import string

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

Opmerking: random.sample voorkomt hergebruik van karakters, het vermenigvuldigen van de grootte van de karakterset maakt meerdere herhalingen mogelijk, maar ze zijn nog steeds minder waarschijnlijk dan in een zuiver willekeurige keuze. Als we gaan voor een string van lengte 6, en we kiezen 'X' als het eerste teken, in het keuzevoorbeeld, is de kans om 'X' te krijgen voor het tweede teken hetzelfde als de kans om 'X' te krijgen als het eerste teken. In de random.sample implementatie is de kans om 'X' als een volgend teken te krijgen slechts 6/7 van de kans om het als het eerste teken te krijgen

Commentaren (10)

Ik dacht dat niemand dit al beantwoord had. Maar hey, hier's mijn eigen poging:

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))], "")
Commentaren (2)