web-dev-qa-db-fra.com

Génération aléatoire de chaînes avec lettres majuscules et chiffres

Je veux générer une chaîne de taille N.

Il doit être composé de chiffres et de lettres majuscules anglaises telles que:

  • 6U1S75
  • 4Z4UKK
  • U911K4

Comment puis-je y parvenir de manière Pythonic ?

1207
Hellnar

Répondez en une ligne:

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

ou même plus court en commençant par Python 3.6 en utilisant random.choices() :

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

Une version cryptographiquement plus sécurisée; voir https://stackoverflow.com/a/23728630/2213647 :

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

En détail, avec une fonction de nettoyage pour une réutilisation ultérieure:

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

Comment ça marche?

Nous importons string, un module contenant des séquences de caractères ASCII communs, et random, un module traitant de la génération aléatoire.

string.ascii_uppercase + string.digits concatène simplement la liste des caractères représentant des majuscules ASCII caractères et chiffres:

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

Ensuite, nous utilisons une compréhension de liste pour créer une liste d'éléments 'n':

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

Dans l'exemple ci-dessus, nous utilisons [ pour créer la liste, mais nous ne le faisons pas dans la fonction id_generator afin que Python ne crée pas la liste en mémoire, mais génère le éléments à la volée, un par un (plus à ce sujet ici ).

Au lieu de demander à créer 'n' fois la chaîne elem, nous demanderons à Python de créer 'n' fois un caractère aléatoire, sélectionné à partir d'une séquence de caractères:

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

Par conséquent, random.choice(chars) for _ in range(size) crée réellement une séquence de size caractères. Caractères choisis au hasard dans 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']

Ensuite, nous les rejoignons avec une chaîne vide afin que la séquence devienne une chaîne:

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

Cette question relative au dépassement de capacité en pile correspond au résultat actuel le plus récent dans Google pour "chaîne aléatoire Python". La principale réponse actuelle est:

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

C'est une excellente méthode, mais le PRNG en mode aléatoire n'est pas sécurisé sur le plan cryptographique. Je suppose que beaucoup de personnes qui recherchent cette question voudront générer des chaînes aléatoires pour le cryptage ou les mots de passe. Vous pouvez le faire en toute sécurité en apportant une petite modification au code ci-dessus:

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

Utiliser random.SystemRandom() au lieu de simplement aléatoire utilise/dev/urandom sur des machines * nix et CryptGenRandom() sous Windows. Ce sont des PRNG sécurisés de manière cryptographique. Utiliser random.choice au lieu de random.SystemRandom().choice dans une application nécessitant un fichier sécurisé PRNG pourrait être dévastateur. Compte tenu de la popularité de cette question, je parie que de nombreuses erreurs ont déjà été commises. .

Si vous utilisez python3.6 ou une version ultérieure, vous pouvez utiliser le nouveau module secrets mentionné dans réponse de MSeifert :

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

La documentation du module décrit également des méthodes pratiques pour générer des jetons sécurisés et meilleures pratiques .

520
Randy Marsh

Utilisez simplement l'uuid intégré de Python:

Si les UUID conviennent à vos besoins, utilisez le package id intégré.

Solution à une ligne:

import uuid; uuid.uuid4().hex.upper()[0:6]

Version détaillée:

Exemple:

import uuid
uuid.uuid4() #uuid4 => full random uuid
# Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')

Si vous avez besoin exactement de votre format (par exemple, "6U1S75"), vous pouvez le faire comme ceci:

import uuid

def my_random_string(string_length=10):
    """Returns a random string of length string_length."""
    random = str(uuid.uuid4()) # Convert UUID format to a Python string.
    random = random.upper() # Make all characters uppercase.
    random = random.replace("-","") # Remove the UUID '-'.
    return random[0:string_length] # Return the random string.

print(my_random_string(6)) # For example, D9E50C
168
Bijan

Une méthode plus simple, plus rapide mais légèrement moins aléatoire consiste à utiliser random.sample au lieu de choisir chaque lettre séparément. Si n répétitions sont autorisées, agrandissez votre base aléatoire de n fois, par exemple.

import random
import string

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

Remarque: random.sample empêche la réutilisation des caractères. Multiplier la taille du jeu de caractères permet plusieurs répétitions, mais elles sont moins probables que dans un choix purement aléatoire. Si nous choisissons une chaîne de longueur 6 et que nous choisissons le premier caractère "X", dans l'exemple de choix, les chances d'obtenir le "X" pour le deuxième caractère sont les mêmes que les chances d'obtenir le "X". premier caractère. Dans l'implémentation random.sample, les chances d'obtenir "X" comme tout caractère ultérieur sont seulement 6/7 chances de l'obtenir comme premier caractère.

44
Anurag Uniyal
import uuid
lowercase_str = uuid.uuid4().hex  

lowercase_str est une valeur aléatoire comme 'cea8b32e00934aaea8c005a35d85a5c0'

uppercase_str = lowercase_str.upper()

uppercase_str est 'CEA8B32E00934AAEA8C005A35D85A5C0'

30
Savad KP

En prenant la réponse de Ignacio, cela fonctionne avec Python 2.6:

import random
import string

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

Exemple de sortie:

JQUBT2

20
quamrana

Une méthode plus rapide, plus simple et plus flexible consiste à utiliser le module strgen (pip install StringGenerator).

Générez une chaîne aléatoire de 6 caractères avec des lettres majuscules et des chiffres:

>>> from strgen import StringGenerator as SG
>>> SG("[\u\d]{6}").render()
u'YZI2CI'

Obtenez une liste unique:

>>> SG("[\l\d]{10}").render_list(5,unique=True)
[u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']

Garantie un caractère "spécial" dans la chaîne:

>>> SG("[\l\d]{10}&[\p]").render()
u'jaYI0bcPG*0'

Une couleur HTML aléatoire:

>>> SG("#[\h]{6}").render()
u'#CEdFCa'

etc.

Nous devons être conscients que ceci:

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

pourrait ne pas contenir un chiffre (ou un caractère majuscule).

strgen est plus rapide en temps développeur que n'importe laquelle des solutions ci-dessus. La solution d’Ignacio est la plus rapide en termes d’exécution et constitue la bonne réponse en utilisant la bibliothèque standard Python. Mais vous ne l'utiliserez presque jamais sous cette forme. Vous voudrez utiliser SystemRandom (ou fallback si non disponible), assurez-vous que les jeux de caractères requis sont représentés, utilisez unicode (ou non), assurez-vous que les appels successifs produisent une chaîne unique, utilisez un sous-ensemble de l'une des classes de caractères du module de chaîne, etc. Tout cela nécessite beaucoup plus de code que dans les réponses fournies. Les différentes tentatives pour généraliser une solution ont toutes des limitations que strgen résout avec plus de brièveté et un pouvoir d’expression plus simple en utilisant un langage de template simple.

C'est sur PyPI:

pip install StringGenerator

Divulgation: Je suis l'auteur du module strgen.

19
Paul Wolf

Basé sur une autre réponse Stack Overflow, Le moyen le plus léger de créer une chaîne aléatoire et un nombre hexadécimal aléatoire, une meilleure version que la réponse acceptée serait:

('%06x' % random.randrange(16**6)).upper()

plus vite.

10
Gubbi

À partir de Python 3.6, vous devez utiliser le module secrets si vous souhaitez qu'il soit cryptographiquement sûr à la place du random module (sinon cette réponse est identique à celle de @Ignacio Vazquez-Abrams):

from secrets import choice
import string

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

Une remarque supplémentaire: une compréhension de liste est plus rapide dans le cas de str.join que d'utiliser une expression génératrice!

10
MSeifert

Je pensais que personne n'avait encore répondu à cela lol! Mais bon, voici le mien:

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))], "")
9
nemesisfixx

Si vous avez besoin d'une chaîne aléatoire plutôt que d'une pseudo-aléatoire , vous devez utiliser os.urandom comme source.

_from os import urandom
from itertools import islice, imap, repeat
import string

def Rand_string(length=5):
    chars = set(string.ascii_uppercase + string.digits)
    char_gen = (c for c in imap(urandom, repeat(1)) if c in chars)
    return ''.join(islice(char_gen, None, length))
_
9
John La Rooy

Cette méthode est légèrement plus rapide et légèrement plus agaçante que la méthode random.choice () publiée par Ignacio.

Il tire parti de la nature des algorithmes pseudo-aléatoires. Il est plus rapide que de générer un nouveau nombre aléatoire pour chaque caractère.

# must be length 32 -- 5 bits -- the question didn't specify using the full set
# of uppercase letters ;)
_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'

def generate_with_randbits(size=32):
    def chop(x):
        while x:
            yield x & 31
            x = x >> 5
    return  ''.join(_ALPHABET[x] for x in chop(random.getrandbits(size * 5))).ljust(size, 'A')

... crée un générateur qui prend 5 nombres de bits à la fois 0..31 jusqu'à ce qu'il n'en reste plus

... rejoindre () les résultats du générateur sur un nombre aléatoire avec les bons bits

Avec Timeit, pour les chaînes de 32 caractères, le timing était le suivant:

[('generate_with_random_choice', 28.92901611328125),
 ('generate_with_randbits', 20.0293550491333)]

... mais pour 64 chaînes de caractères, randbits perd;)

Je n'utiliserais probablement jamais cette approche dans le code de production à moins que je n'aime vraiment pas mes collègues.

edit: mis à jour en fonction de la question (majuscules et chiffres uniquement), et utilise les opérateurs au niveau des bits & et >> au lieu de% et //

7
Rob

Je le ferais de cette façon:

import random
from string import digits, ascii_uppercase

legals = digits + ascii_uppercase

def Rand_string(length, char_set=legals):

    output = ''
    for _ in range(length): output += random.choice(char_set)
    return output

Ou juste:

def Rand_string(length, char_set=legals):

    return ''.join( random.choice(char_set) for _ in range(length) )
5
Carl Smith

Utilisez la fonction random.choice () de Numpy

import numpy as np
import string        

if __== '__main__':
    length = 16
    a = np.random.choice(list(string.ascii_uppercase + string.digits), length)                
    print(''.join(a))

La documentation est ici http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html

4
Mudit Jain
>>> import string 
>>> import random

la logique suivante génère toujours un échantillon aléatoire de 6 caractères

>>> print ''.join(random.sample((string.ascii_uppercase+string.digits),6))
JT7K3Q

Pas besoin de multiplier par 6

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

TK82HK
4
user128956

(1) Cela vous donnera toutes les majuscules et numéros:

import string, random
passkey=''
for x in range(8):
    if random.choice([1,2]) == 1:
        passkey += passkey.join(random.choice(string.ascii_uppercase))
    else:
        passkey += passkey.join(random.choice(string.digits))
print passkey 

(2) Si vous souhaitez ultérieurement inclure des lettres minuscules dans votre clé, cela fonctionnera également:

import string, random
passkey=''
for x in range(8):
    if random.choice([1,2]) == 1:
        passkey += passkey.join(random.choice(string.ascii_letters))
    else:
        passkey += passkey.join(random.choice(string.digits))
print passkey  
3
Jacob

c’est une interprétation de la réponse d’Anurag Uniyal et une chose sur laquelle je travaillais moi-même.

import random
import string

oneFile = open('‪Numbers.txt', 'w')
userInput = 0
key_count = 0
value_count = 0
chars = string.ascii_uppercase + string.digits + string.punctuation

for userInput in range(int(input('How many 12 digit keys do you want?'))):
    while key_count <= userInput:
        key_count += 1
        number = random.randint(1, 999)
        key = number

        text = str(key) + ": " + str(''.join(random.sample(chars*6, 12)))
        oneFile.write(text + "\n")
oneFile.close()
3
Stopit Donk

Pour ceux qui aiment le python fonctionnel:

from itertools import imap, starmap, islice, repeat
from functools import partial
from string import letters, digits, join
from random import choice

join_chars = partial(join, sep='')
identity = lambda o: o

def irand_seqs(symbols=join_chars((letters, digits)), length=6, join=join_chars, select=choice, breakup=islice):
    """ Generates an indefinite sequence of joined random symbols each of a specific length
    :param symbols: symbols to select,
        [defaults to string.letters + string.digits, digits 0 - 9, lower and upper case English letters.]
    :param length: the length of each sequence,
        [defaults to 6]
    :param join: method used to join selected symbol, 
        [defaults to ''.join generating a string.]
    :param select: method used to select a random element from the giving population. 
        [defaults to random.choice, which selects a single element randomly]
    :return: indefinite iterator generating random sequences of giving [:param length]
    >>> from tools import irand_seqs
    >>> strings = irand_seqs()
    >>> a = next(strings)
    >>> assert isinstance(a, (str, unicode))
    >>> assert len(a) == 6
    >>> assert next(strings) != next(strings)
    """
    return imap(join, starmap(breakup, repeat((imap(select, repeat(symbols)), None, length))))

Il génère un itérateur [infini] indéfini, de séquences aléatoires jointes, en générant d’abord une séquence indéfinie de symbole sélectionné de manière aléatoire dans le pool donneur, puis divise cette séquence en parties de longueur qui sont ensuite jointes. Elle doit fonctionner avec toute séquence prenant en charge getitem. , par défaut, il génère simplement une séquence aléatoire de lettres alphanumériques, bien que vous puissiez facilement le modifier pour générer d’autres choses:

par exemple pour générer des tuples aléatoires de chiffres:

>>> irand_tuples = irand_seqs(xrange(10), join=Tuple)
>>> next(irand_tuples)
(0, 5, 5, 7, 2, 8)
>>> next(irand_tuples)
(3, 2, 2, 0, 3, 1)

si vous ne voulez pas utiliser next for generation, vous pouvez simplement le rendre appelable:

>>> irand_tuples = irand_seqs(xrange(10), join=Tuple)
>>> make_Rand_tuples = partial(next, irand_tuples) 
>>> make_Rand_tuples()
(1, 6, 2, 8, 1, 9)

si vous voulez générer la séquence à la volée, définissez simplement join à identité.

>>> irand_tuples = irand_seqs(xrange(10), join=identity)
>>> selections = next(irand_tuples)
>>> next(selections)
8
>>> list(selections)
[6, 3, 8, 2, 2]

Comme d'autres l'ont mentionné si vous avez besoin de plus de sécurité, définissez la fonction de sélection appropriée:

>>> from random import SystemRandom
>>> Rand_strs = irand_seqs(select=SystemRandom().choice)
'QsaDxQ'

le sélecteur par défaut est choice qui peut sélectionner le même symbole plusieurs fois pour chaque bloc, si vous préférez que le même membre soit sélectionné au plus une fois pour chaque bloc, une utilisation possible:

>>> from random import sample
>>> irand_samples = irand_seqs(xrange(10), length=1, join=next, select=lambda pool: sample(pool, 6))
>>> next(irand_samples)
[0, 9, 2, 3, 1, 6]

nous utilisons sample comme sélecteur pour faire la sélection complète. Les morceaux ont donc une longueur de 1; pour nous rejoindre, nous appelons simplement next qui récupère le prochain bloc entièrement généré, à supposer que cet exemple semble un peu encombrant et c'est ...

3
Samy Vilar
import random
q=2
o=1
list  =[r'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','s','0','1','2','3','4','5','6','7','8','9','0']
while(q>o):
    print("")

    for i in range(1,128):
        x=random.choice(list)
        print(x,end="")

Ici, la longueur de la chaîne peut être modifiée dans la boucle i.e pour i dans la plage (1, longueur). C'est un algorithme simple, facile à comprendre. il utilise la liste afin que vous puissiez supprimer les caractères dont vous n’avez pas besoin.

2
lawlie8
import string
from random import *
characters = string.ascii_letters + string.punctuation  + string.digits
password =  "".join(choice(characters) for x in range(randint(8, 16)))
print password
2
Natasha
>>> import random
>>> str = []
>>> chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
>>> num = int(raw_input('How long do you want the string to be?  '))
How long do you want the string to be?  10
>>> for k in range(1, num+1):
...    str.append(random.choice(chars))
...
>>> str = "".join(str)
>>> str
'tm2JUQ04CK'

La fonction random.choice sélectionne une entrée aléatoire dans une liste. Vous créez également une liste pour pouvoir ajouter le caractère dans l'instruction for. À la fin, str est ['t', 'm', '2', 'J', 'U', 'Q', '0', '4', 'C', 'K'], mais le str = "".join(str) s'en charge, vous laissant avec 'tm2JUQ04CK'.

J'espère que cela t'aides!

2
A.J. Uppal

Parfois 0 (zéro) & O (lettre O) peuvent être déroutants. Donc j'utilise

import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')
1
Aseem

Un simple:

import string
import random
character = string.lowercase + string.uppercase + string.digits + string.punctuation
char_len = len(character)
# you can specify your password length here
pass_len = random.randint(10,20)
password = ''
for x in range(pass_len):
    password = password + character[random.randint(0,char_len-1)]
print password
1
Hackaholic

J'ai consulté presque toutes les réponses, mais aucune ne semble plus facile. Je vous suggère d'essayer la bibliothèque passgen qui est généralement utilisée pour créer des mots de passe aléatoires.

Vous pouvez générer des chaînes aléatoires de votre choix de longueur , de ponctuation, de chiffres, de lettres et de .

Voici le code pour votre cas:

from passgen import passgen
string_length = int(input())
random_string = passgen(length=string_length, punctuation=False, digits=True, letters=True, case='upper')
0
Sukumar Rdjf

Deux méthodes:

import random, math
def randStr_1(chars:str, length:int) -> str:
    chars *= math.ceil(length / len(chars))
    chars = letters[0:length]
    chars = list(chars)
    random.shuffle(characters)

    return ''.join(chars)
def randStr_2(chars:str, length:int) -> str:
    return ''.join(random.choice(chars) for i in range(chars))


Benchmark:

from timeit import timeit

setup = """
import os, subprocess, time, string, random, math

def randStr_1(letters:str, length:int) -> str:
    letters *= math.ceil(length / len(letters))
    letters = letters[0:length]
    letters = list(letters)
    random.shuffle(letters)
    return ''.join(letters)

def randStr_2(letters:str, length:int) -> str:
    return ''.join(random.choice(letters) for i in range(length))
"""

print('Method 1 vs Method 2', ', run 10 times each.')

for length in [100,1000,10000,50000,100000,500000,1000000]:
    print(length, 'characters:')

    eff1 = timeit("randStr_1(string.ascii_letters, {})".format(length), setup=setup, number=10)
    eff2 = timeit("randStr_2(string.ascii_letters, {})".format(length), setup=setup, number=10)
    print('\t{}s : {}s'.format(round(eff1, 6), round(eff2, 6)))
    print('\tratio = {} : {}\n'.format(eff1/eff1, round(eff2/eff1, 2)))

Sortie:

Method 1 vs Method 2 , run 10 times each.

100 characters:
    0.001411s : 0.00179s
    ratio = 1.0 : 1.27

1000 characters:
    0.013857s : 0.017603s
    ratio = 1.0 : 1.27

10000 characters:
    0.13426s : 0.151169s
    ratio = 1.0 : 1.13

50000 characters:
    0.709403s : 0.855136s
    ratio = 1.0 : 1.21

100000 characters:
    1.360735s : 1.674584s
    ratio = 1.0 : 1.23

500000 characters:
    6.754923s : 7.160508s
    ratio = 1.0 : 1.06

1000000 characters:
    11.232965s : 14.223914s
    ratio = 1.0 : 1.27

La performance de la première méthode est meilleure.

0
Bi Ao

Je voudrais vous suggérer la prochaine option:

import crypt
n = 10
crypt.crypt("any sring").replace('/', '').replace('.', '').upper()[-n:-1]

Mode paranoïque:

import uuid
import crypt
n = 10
crypt.crypt(str(uuid.uuid4())).replace('/', '').replace('.', '').upper()[-n:-1]
0
mrvol

pour python 3 chaîne d'importation, aléatoire

'' .join (random.choice (string.ascii_lowercase + string.ascii_uppercase + string.digits) pour _ dans la plage (15))

0
Foki