Я хочу сгенерировать строку размером N.
Он должен состоять из цифр и заглавных букв английского алфавита, таких как:
- 6U1S75
- 4Z4UKK
- U911K4
Как я могу достичь этого питонским способом?
Я хочу сгенерировать строку размером N.
Он должен состоять из цифр и заглавных букв английского алфавита, таких как:
Как я могу достичь этого питонским способом?
Ответы:
Ответ в одной строке:
''.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))
Криптографически более безопасная версия; см. https://stackoverflow.com/a/23728630/2213647 :
''.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'
range
на xrange
.
random
на random.SystemRandom()
: github.com/django/django/blob/…
random.sample
создает образцы без замены, другими словами, без возможности повторения символов, что не соответствует требованиям ОП. Я не думаю, что это было бы желательно для большинства приложений.
Этот вопрос переполнения стека является текущим лучшим результатом 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()
в Windows. Это криптографически безопасные PRNG. Использование random.choice
вместо random.SystemRandom().choice
приложения, которое требует защищенного PRNG, может быть потенциально разрушительным, и, учитывая популярность этого вопроса, я уверен, что ошибка уже была совершена много раз.
Если вы используете python3.6 или выше, вы можете использовать новый модуль секретов, как указано в ответе MSeifert :
''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))
В модуле также обсуждаются удобные способы создания безопасных токенов и лучшие практики .
random
предупреждает это: « Предупреждение : генераторы псевдослучайных чисел этого модуля не должны использоваться в целях безопасности. Используйте os.urandom () или SystemRandom, если вам требуется криптографически безопасный генератор псевдослучайных чисел. " Вот ссылка: random.SystemRandom и os.urandom
string.uppercase
что может привести к неожиданным результатам в зависимости от установленного языкового стандарта. Использование string.ascii_uppercase
(или string.ascii_letters + string.digits
для base62 вместо base36) более безопасно в случаях, когда используется кодирование.
xrange
вместо того, range
чтобы последний генерировал список в памяти, тогда как первый создает итератор.
Если UUID подходят для ваших целей, используйте встроенный пакет uuid .
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
string_length
, вероятность столкновения может быть проблемой.
Более простой, быстрый, но немного менее случайный способ состоит в том, чтобы использовать 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 шанс получить его в качестве первого символа
sample
вы никогда не получите один и тот же символ в списке дважды. Также, конечно, это не удастся для N
выше, чем 36
.
import uuid
lowercase_str = uuid.uuid4().hex
lowercase_str
это случайное значение, как 'cea8b32e00934aaea8c005a35d85a5c0'
uppercase_str = lowercase_str.upper()
uppercase_str
является 'CEA8B32E00934AAEA8C005A35D85A5C0'
uppercase_str[:N+1]
Более быстрый, простой и гибкий способ сделать это - использовать 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 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
чем использование выражения-генератора!
Основываясь на другом ответе о переполнении стека, самый простой способ создания случайной строки и случайного шестнадцатеричного числа , лучшая версия, чем принятый ответ:
('%06x' % random.randrange(16**6)).upper()
намного быстрее.
N
.
Если вам нужна случайная строка, а не псевдослучайная , вы должны использовать 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))
os.urandom
не псевдослучайный? Возможно, он использует лучший алгоритм для генерации более случайных чисел, но он все еще псевдослучайный.
/dev/random
и /dev/urandom
. Проблема в том, что /dev/random
блокирует, когда энтропии недостаточно, что ограничивает ее полезность. Для однократного пэда /dev/urandom
недостаточно, но я думаю, что здесь лучше, чем псевдослучайный.
/dev/random
и /dev/urandom
псевдослучайны, но это может зависеть от вашего определения.
Я думал, что никто еще не ответил на это, лол! Но эй, вот мой собственный взгляд на это:
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))], "")
Этот метод немного быстрее и немного раздражает, чем метод 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 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) )
Используйте функцию 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 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
Для тех из вас, кто любит функциональный питон:
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
который выбирает следующий полностью сгенерированный чанк, при условии, что этот пример кажется немного громоздким, и это ...
(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
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()
>>> 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'
.
Надеюсь это поможет!
range(num)
вместо этого, и str мог бы быть строкой str += random.choice(chars)
.
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 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
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 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
Производительность первого метода лучше.
Я прошел почти все ответы, но ни один из них не выглядит проще. Я бы предложил вам попробовать Passgen библиотеку которая обычно используется для создания случайных паролей.
Вы можете генерировать случайные строки по вашему выбору длины, пунктуации, цифр, букв и регистра.
Вот код для вашего случая:
from passgen import passgen
string_length = int(input())
random_string = passgen(length=string_length, punctuation=False, digits=True, letters=True, case='upper')
Генерация случайного 16-байтового идентификатора, содержащего буквы, цифры, '_' и '-'
os.urandom(16).translate((f'{string.ascii_letters}{string.digits}-_'*4).encode('ascii'))
Я смотрел на разные ответы и нашел время, чтобы прочитать документацию секретов
Модуль секретов используется для генерации криптографически стойких случайных чисел, подходящих для управления такими данными, как пароли, аутентификация учетной записи, токены безопасности и связанные секреты.
В частности, секреты следует использовать вместо генератора псевдослучайных чисел по умолчанию в модуле случайных чисел, который предназначен для моделирования и симуляции, а не для защиты или криптографии.
Более подробно рассмотрев, что он может предложить, я нашел очень удобную функцию, если вы хотите имитировать такой идентификатор, как идентификаторы Google Drive:
secrets.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
Я знаю, что это немного отличается от вопроса ОП, но я ожидаю, что это все равно будет полезно для многих, кто искал тот же вариант использования, который я искал.
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
Я обнаружил, что это проще и чище.
str_Key = ""
str_FullKey = ""
str_CharacterPool = "01234ABCDEFfghij~>()"
for int_I in range(64):
str_Key = random.choice(str_CharacterPool)
str_FullKey = str_FullKey + str_Key
Просто измените 64, чтобы изменить длину, измените CharacterPool, чтобы он делал буквенно-цифровые, буквенно-цифровые или странные символы или что угодно.