Генерация случайных строк с прописными буквами и цифрами в Python
Я хочу сгенерировать строку размером N.
Он должен состоять из цифр и заглавных букв английского алфавита, таких как:
- 6U1S75
- 4Z4UKK
- U911K4
Как я могу достичь этого питонским способом?
41 ответ
Ответ в одной строке:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
или даже короче, начиная с Python 3.6, используя random.choices()
:
''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
Криптографически более безопасная версия;см. /questions/843187/generatsiya-sluchajnyih-strok-s-propisnyimi-bukvami-i-tsiframi-v-python/843214#843214:
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
Подробно, с чистой функцией для дальнейшего повторного использования:
>>> 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'
Как это работает?
Мы импортируем string
модуль, содержащий последовательности общих символов ASCII, и random
модуль, который имеет дело со случайной генерацией.
string.ascii_uppercase + string.digits
просто объединяет список символов, представляющих символы и цифры ASCII в верхнем регистре:
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
Затем мы используем понимание списка, чтобы создать список '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']
В приведенном выше примере мы используем [
создать список, но мы не в id_generator
функция, поэтому Python не создает список в памяти, но генерирует элементы на лету, один за другим (подробнее об этом здесь).
Вместо того, чтобы просить создать 'n' раз строку elem
, мы попросим Python создать n раз случайный символ, выбранный из последовательности символов:
>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'
Следовательно random.choice(chars) for _ in range(size)
на самом деле создает последовательность size
персонажи. Персонажи, случайно выбранные из 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']
Затем мы просто соединяем их пустой строкой, чтобы последовательность стала строкой:
>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Этот вопрос переполнения стека является текущим лучшим результатом Google для "случайной строки Python". Текущий топ-ответ:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
Это отличный метод, но случайный PRNG не является криптографически безопасным. Я предполагаю, что многие люди, исследующие этот вопрос, захотят генерировать случайные строки для шифрования или паролей. Вы можете сделать это безопасно, внеся небольшое изменение в приведенный выше код:
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
С помощью random.SystemRandom()
вместо случайного использования /dev/urandom на *nix машинах и CryptGenRandom()
в винде. Это криптографически безопасные PRNG. С помощью random.choice
вместо random.SystemRandom().choice
в приложении, которое требует защищенного PRNG, может быть потенциально разрушительным, и, учитывая популярность этого вопроса, я уверен, что ошибка уже совершалась много раз.
Если вы используете python3.6 или выше, вы можете использовать новый модуль секретов.
''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))
В модуле также обсуждаются удобные способы создания безопасных токенов и лучшие практики.
Просто используйте встроенный в Python uuid:
Если UUID подходят для ваших целей, используйте встроенный пакет uuid.
Решение One Line:
import uuid; uuid.uuid4().hex.upper()[0:6]
В глубокой версии:
Пример:
import uuid
uuid.uuid4() #uuid4 => full random uuid
# Outputs something like: UUID('0172fc9a-1dac-4414-b88d-6b9a6feb91ea')
Если вам нужен именно ваш формат (например, "6U1S75"), вы можете сделать это следующим образом:
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
Более простой, быстрый, но немного менее случайный способ заключается в использовании random.sample
вместо того, чтобы выбирать каждую букву отдельно, если разрешено n-повторений, увеличьте ваш случайный базис в n раз, например
import random
import string
char_set = string.ascii_uppercase + string.digits
print ''.join(random.sample(char_set*6, 6))
Примечание: random.sample предотвращает повторное использование символов, умножение размера набора символов делает возможным многократное повторение, но они все же менее вероятны, чем при чисто случайном выборе. Если мы выберем строку длиной 6 и выберем "X" в качестве первого символа, в примере выбора шансы получить "X" для второго символа такие же, как шансы получить "X" в качестве первый персонаж В реализации random.sample шансы получить 'X' в качестве любого последующего символа составляют лишь 6/7 шанс получить его в качестве первого символа
import uuid
lowercase_str = uuid.uuid4().hex
lowercase_str
это случайное значение, как 'cea8b32e00934aaea8c005a35d85a5c0'
uppercase_str = lowercase_str.upper()
uppercase_str
является 'CEA8B32E00934AAEA8C005A35D85A5C0'
Начиная с версии Python 3.6 вы должны использовать secrets
модуль, если вам нужно, чтобы он был криптографически защищен вместо random
модуль (в противном случае этот ответ идентичен ответу @Ignacio Vazquez-Abrams):
from secrets import choice
import string
''.join([choice(string.ascii_uppercase + string.digits) for _ in range(N)])
Еще одно примечание: понимание списка происходит быстрее в случае str.join
чем с помощью выражения генератора!
Более быстрый, простой и гибкий способ сделать это - использовать strgen
модуль (pip install StringGenerator
).
Создайте случайную строку из 6 символов с заглавными буквами и цифрами:
>>> from strgen import StringGenerator as SG
>>> SG("[\u\d]{6}").render()
u'YZI2CI'
Получить уникальный список:
>>> SG("[\l\d]{10}").render_list(5,unique=True)
[u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']
Гарантия одного "специального" символа в строке:
>>> SG("[\l\d]{10}&[\p]").render()
u'jaYI0bcPG*0'
Случайный цвет HTML:
>>> SG("#[\h]{6}").render()
u'#CEdFCa'
и т.п.
Мы должны знать, что это:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
может не иметь цифры (или заглавные буквы) в нем.
strgen
быстрее во время разработки, чем любое из вышеуказанных решений. Решение от Ignacio является самым быстродействующим во время выполнения и является правильным ответом при использовании стандартной библиотеки Python. Но вы вряд ли когда-либо будете использовать его в такой форме. Вы захотите использовать SystemRandom (или использовать запасной вариант, если он недоступен), убедиться, что требуемые наборы символов представлены, использовать юникод (или нет), убедиться, что последовательные вызовы создают уникальную строку, использовать подмножество одного из классов символов модуля строки, и т. д. Все это требует гораздо больше кода, чем в ответах. Различные попытки обобщить решение имеют ограничения, которые strgen решает с большей краткостью и выразительностью, используя простой язык шаблонов.
Это на PyPI:
pip install StringGenerator
Раскрытие информации: я являюсь автором модуля strgen.
Принимая ответ от Игнасио, это работает с Python 2.6:
import random
import string
N=6
print ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
Пример вывода:
JQUBT2
Основываясь на другом ответе о переполнении стека, самый простой способ создания случайной строки и случайного шестнадцатеричного числа, лучшая версия, чем принятый ответ:
('%06x' % random.randrange(16**6)).upper()
намного быстрее.
Я думал, что никто еще не ответил на это, лол! Но эй, вот мой собственный взгляд на это:
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))], "")
Если вам нужна случайная строка, а не псевдослучайная, вы должны использовать os.urandom
как источник
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))
Этот метод немного быстрее и немного раздражает, чем метод random.choice(), опубликованный Игнасио.
Он использует преимущества природы псевдослучайных алгоритмов и делает ставку на биты и сдвигается быстрее, чем генерация нового случайного числа для каждого символа.
# 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')
... создать генератор, который вынимает 5-битные числа за раз 0..31, пока не останется ни одного
...join() результаты генератора по случайному числу с правильными битами
С Timeit для 32-символьных строк время было:
[('generate_with_random_choice', 28.92901611328125),
('generate_with_randbits', 20.0293550491333)]
... но для 64 строк символов рандбиты проигрывают;)
Я бы, вероятно, никогда не использовал бы этот подход в рабочем коде, если бы мне действительно не нравились мои коллеги.
edit: обновлен в соответствии с вопросом (только в верхнем регистре и цифрах) и использует побитовые операторы & и >> вместо% и //
Подход, ориентированный на безопасность
Наша рекомендация для всего, что связано с безопасностью, состоит в том, чтобы избегать «перекатывания собственных» и использовать модуль секретов, который специально проверен на предмет безопасности.
Это из раздела лучших практик документации :
import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))
Поскольку вы специально просили заглавные буквы, вы можете либо заменить
ascii_uppercase
за
ascii_letters
или просто введите пароль в верхнем регистре:
password = password.upper()
Стандартный подход, не направленный на безопасность
Канонический подход к этой проблеме (как указано) использует функцию selections() в модуле random:
>>> from random import choices
>>> from string import ascii_uppercase, digits
>>> population = ascii_uppercase + digits
>>> str.join('', choices(population, k=6))
'6JWF1H'
Используйте функцию random.choice() от Numpy
import numpy as np
import string
if __name__ == '__main__':
length = 16
a = np.random.choice(list(string.ascii_uppercase + string.digits), length)
print(''.join(a))
Документация находится здесь http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.random.choice.html
Я бы сделал это так:
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
Или просто:
def rand_string(length, char_set=legals):
return ''.join( random.choice(char_set) for _ in range(length) )
Иногда 0 (ноль) и O (буква O) могут сбивать с толку. Поэтому я использую
import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')
>>> import string
>>> import random
следующая логика все еще генерирует случайную выборку из 6 символов
>>> print ''.join(random.sample((string.ascii_uppercase+string.digits),6))
JT7K3Q
Не нужно умножать на 6
>>> print ''.join(random.sample((string.ascii_uppercase+string.digits)*6,6))
TK82HK
Я использовал этот метод для генерации случайной строки длины n от a -> z
Я просматривал разные ответы и нашел время, чтобы прочитать документацию по секретам
Модуль секретов используется для генерации криптографически стойких случайных чисел, подходящих для управления такими данными, как пароли, аутентификация учетной записи, токены безопасности и связанные с ними секреты.
В частности, секреты следует использовать вместо генератора псевдослучайных чисел по умолчанию в модуле случайных чисел, который предназначен для моделирования и симуляции, а не для безопасности или криптографии.
Подробнее о том, что он может предложить, я нашел очень удобную функцию, если вы хотите имитировать идентификатор, такой как идентификаторы Google Диска:
secretts.token_urlsafe([nbytes=None])
Возвращает случайную безопасную для URL текстовую строку, содержащую n байтов случайных байтов. Текст закодирован в Base64, поэтому в среднем каждый байт соответствует примерно 1,3 символа. Если nbytes равен None или не указан, используется разумное значение по умолчанию.
Используйте это следующим образом:
import secrets
import math
def id_generator():
id = secrets.token_urlsafe(math.floor(32 / 1.3))
return id
print(id_generator())
Выведите идентификатор длиной 32 символа:
joXR8dYbBDAHpVs5ci6iD-oIgPhkeQFk
Я знаю, что это немного отличается от вопроса OP, но я ожидаю, что он по-прежнему будет полезен для многих, кто искал тот же вариант использования, который искал я.
Это ответ на ответ Анурага Униьяла и то, над чем я работал сам.
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()
(1) Это даст вам все заглавные буквы и цифры:
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) Если позже вы захотите включить строчные буквы в свой ключ, то это также будет работать:
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
>>> 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'
random.choice
Функция выбирает случайную запись в списке. Вы также создаете список, так что вы можете добавить символ в for
заявление. В конце str это ['t', 'm', '2', 'J', 'U', 'Q', '0', '4', 'C', 'K'], но str = "".join(str)
заботится об этом, оставляя вас с 'tm2JUQ04CK'
,
Надеюсь это поможет!
Для тех из вас, кто любит функциональный питон:
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))))
Он генерирует неопределенный [бесконечный] итератор из соединенных случайных последовательностей, сначала генерируя неопределенную последовательность случайно выбранных символов из пула-получателя, затем разбивая эту последовательность на части длины, которые затем соединяются, он должен работать с любой последовательностью, поддерживающей getitem. по умолчанию он просто генерирует случайную последовательность буквенно-цифровых букв, хотя вы можете легко изменить ее для создания других вещей:
например, для генерации случайных наборов цифр:
>>> 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)
если вы не хотите использовать next для поколения, вы можете просто сделать его вызываемым:
>>> irand_tuples = irand_seqs(xrange(10), join=tuple)
>>> make_rand_tuples = partial(next, irand_tuples)
>>> make_rand_tuples()
(1, 6, 2, 8, 1, 9)
если вы хотите сгенерировать последовательность на лету, просто установите соединение в идентичность.
>>> irand_tuples = irand_seqs(xrange(10), join=identity)
>>> selections = next(irand_tuples)
>>> next(selections)
8
>>> list(selections)
[6, 3, 8, 2, 2]
Как уже упоминали другие, если вам нужно больше безопасности, установите соответствующую функцию выбора:
>>> from random import SystemRandom
>>> rand_strs = irand_seqs(select=SystemRandom().choice)
'QsaDxQ'
селектор по умолчанию choice
который может выбирать один и тот же символ несколько раз для каждого чанка, если вместо этого вы хотите, чтобы один и тот же элемент выбирался не более одного раза для каждого чанка, одно из возможных применений:
>>> 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]
мы используем sample
как наш селектор, чтобы сделать полный выбор, так что куски на самом деле длина 1, и чтобы присоединиться, мы просто вызываем next
который выбирает следующий полностью сгенерированный кусок, при условии, что этот пример кажется немного громоздким, и это...
Сгенерировать случайный 16-байтовый идентификатор, содержащий буквы, цифры, '_' и '-'
os.urandom(16).translate((f'{string.ascii_letters}{string.digits}-_'*4).encode('ascii'))
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="")
Здесь длина строки может быть изменена для цикла for, т.е. для i в диапазоне (1, длина). Это простой алгоритм, который легко понять. он использует список, так что вы можете отказаться от символов, которые вам не нужны.
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
Простой:
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
import string, random
lower = string.ascii_lowercase
upper = string.ascii_uppercase
digits = string.digits
special = '!"£$%^&*.,@#/?'
def rand_pass(l=4, u=4, d=4, s=4):
p = []
[p.append(random.choice(lower)) for x in range(l)]
[p.append(random.choice(upper)) for x in range(u)]
[p.append(random.choice(digits)) for x in range(d)]
[p.append(random.choice(special)) for x in range(s)]
random.shuffle(p)
return "".join(p)
print(rand_pass())
# @5U,@A4yIZvnp%51
Я хотел бы предложить вам следующий вариант:
import crypt
n = 10
crypt.crypt("any sring").replace('/', '').replace('.', '').upper()[-n:-1]
Параноидальный режим:
import uuid
import crypt
n = 10
crypt.crypt(str(uuid.uuid4())).replace('/', '').replace('.', '').upper()[-n:-1]
Два метода:
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))
Контрольный показатель:
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)))
Выход:
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
Производительность первого метода лучше.