包含大写字母和数字的随机字符串生成
- 2024-12-05 08:38:00
- admin 原创
- 138
问题描述:
如何生成一个由数字和大写英文字母组成的大小为 N 的字符串,例如:
6U1S75
4Z4UKK
U911K4
解决方案 1:
一行回答:
''.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))
加密上更安全的版本: 参见此文章
''.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'
解决方案 2:
这个 Stack Overflow 问题是“随机字符串 Python”当前 Google 搜索结果中的最佳结果。当前最佳答案是:
''.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))
在 *nix 机器和 Windows 上,使用random.SystemRandom()
而不是 random 会使用 /dev/urandom CryptGenRandom()
。这些是加密安全的 PRNG。在需要安全 PRNG 的应用程序中,使用random.choice
而不是random.SystemRandom().choice
可能会造成潜在的破坏,考虑到这个问题的流行程度,我敢打赌这个错误已经犯了很多次了。
如果您使用的是 python3.6 或更高版本,则可以使用MSeifert 的回答中提到的新secrets模块:
''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))
模块文档还讨论了生成安全令牌的便捷方法和最佳实践。
解决方案 3:
只需使用 Python 的内置 uuid:
如果 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
解决方案 4:
一种更好的方法可以被认为更快但随机性稍差,那就是使用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
解决方案 5:
import uuid
lowercase_str = uuid.uuid4().hex
lowercase_str
是一个随机值,例如'cea8b32e00934aaea8c005a35d85a5c0'
uppercase_str = lowercase_str.upper()
uppercase_str
是'CEA8B32E00934AAEA8C005A35D85A5C0'
解决方案 6:
从 Python 3.6 开始,如果您需要它具有加密安全性,则应该使用secrets 模块 而不是模块(否则这个答案与@Ignacio Vazquez-Abrams 的答案相同):random
from secrets import choice
import string
''.join([choice(string.ascii_uppercase + string.digits) for _ in range(N)])
另外需要注意的是:使用列表推导比str.join
使用生成器表达式更快!
解决方案 7:
更快、更简单、更灵活的方法是使用模块strgen
(pip install StringGenerator
)。
生成一个由大写字母和数字组成的 6 个随机字符串:
>>> from strgen import StringGenerator as SG
>>> SG("[/ud]{6}").render()
u'YZI2CI'
获取唯一列表:
>>> SG("[ld]{10}").render_list(5,unique=True)
[u'xqqtmi1pOk', u'zmkWdUr63O', u'PGaGcPHrX2', u'6RZiUbkk2i', u'j9eIeeWgEF']
保证字符串中有一个“特殊”字符:
>>> SG("[ld]{10}&[p]").render()
u'jaYI0bcPG*0'
随机 HTML 颜色:
>>> SG("#[h]{6}").render()
u'#CEdFCa'
ETC。
我们需要意识到这一点:
''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))
其中可能没有数字(或大写字符)。
strgen
在开发时间上比上述任何解决方案都快。Ignacio 的解决方案是运行时执行速度最快的,并且是使用 Python 标准库的正确答案。但您几乎不会以这种形式使用它。您将需要使用 SystemRandom(或回退,如果不可用),确保所需的字符集被表示,使用 unicode(或不使用),确保连续调用产生唯一的字符串,使用字符串模块字符类之一的子集等。所有这些都需要比提供的答案更多的代码。各种概括解决方案的尝试都有局限性,strgen 使用简单的模板语言以更简洁和更强大的表现力解决了这些问题。
它在 PyPI 上:
pip install StringGenerator
披露:我是 strgen 模块的作者。
解决方案 8:
根据另一个 Stack Overflow 的答案,创建随机字符串和随机十六进制数的最轻量级方法,比接受的答案更好的版本是:
('%06x' % random.randrange(16**6)).upper()
更快。
解决方案 9:
安全导向方法
对于任何与安全相关的问题,我们的建议是避免“自行解决”,并使用专门经过安全审查的秘密模块。
这是来自文档的最佳实践部分:
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()
标准方法不以安全为目标
解决该问题的规范方法(如指定)是使用随机模块中的choices()函数:
>>> from random import choices
>>> from string import ascii_uppercase, digits
>>> population = ascii_uppercase + digits
>>> str.join('', choices(population, k=6))
'6JWF1H'
解决方案 10:
我以为还没有人回答这个问题哈哈!但是嘿,这是我自己的尝试:
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))], "")
解决方案 11:
如果你需要一个随机字符串而不是伪随机字符串,你应该使用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))
解决方案 12:
与 Ignacio 发布的 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 个字符的字符串,randbits 失败了;)
除非我真的不喜欢我的同事,否则我可能永远不会在生产代码中使用这种方法。
编辑:更新以适合问题(仅限大写和数字),并使用按位运算符 & 和 >> 而不是 % 和 //
解决方案 13:
使用 Numpy 的 random.choice() 函数
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
解决方案 14:
我会这样做:
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) )
解决方案 15:
有时 0(零)和 O(字母 O)可能会令人困惑。所以我使用
import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')
解决方案 16:
>>> 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
解决方案 17:
我使用此方法从 a -> z 生成长度为 n 的随机字符串
import random
s = ''.join(random.choice([chr(i) for i in range(ord('a'),ord('z'))]) for _ in range(10))
运行代码片段Hide results展开片段
解决方案 18:
>>> 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'
。
希望这有帮助!
解决方案 19:
对于那些喜欢函数式 Python 的人来说:
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)
如果你不想使用下一代,你可以简单地使其可调用:
>>> 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
它即可获取下一个完全生成的块,当然这个例子看起来有点麻烦而且它是......
解决方案 20:
(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
解决方案 21:
这是对 Anurag Uniyal 的回应的看法,也是我自己正在研究的事情。
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 + "
")
oneFile.close()
解决方案 22:
我查看了不同的答案,并花时间阅读了秘密的文件
机密模块用于生成适合管理密码、帐户身份验证、安全令牌和相关机密等数据的加密强随机数。
具体来说,应该优先使用秘密而不是随机模块中默认的伪随机数生成器,它是为建模和模拟而设计的,而不是为安全或加密而设计的。
进一步了解它提供的功能后,我发现如果你想模仿像 Google Drive ID 这样的 ID,它有一个非常方便的功能:
secrets.token_urlsafe([nbytes=None])
返回一个随机的 URL 安全文本字符串,包含 nbytes 个随机字节。文本采用 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个字符长度的id:
joXR8dYbBDAHpVs5ci6iD-oIgPhkeQFk
我知道这与 OP 的问题略有不同,但我希望它对于许多正在寻找与我相同用例的人来说仍然有帮助。
解决方案 23:
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
解决方案 24:
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 循环中更改字符串的长度,即 for i in range(1,length) 这是一个简单的算法,易于理解。它使用列表,因此您可以丢弃不需要的字符。
解决方案 25:
生成包含字母、数字、“_”和“-”的随机 16 字节 ID
os.urandom(16).translate((f'{string.ascii_letters}{string.digits}-_'*4).encode('ascii'))
解决方案 26:
简单来说:
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
解决方案 27:
我想向您推荐下一个选项:
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]
解决方案 28:
两种方法:
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(' {}s : {}s'.format(round(eff1, 6), round(eff2, 6)))
print(' ratio = {} : {}
'.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
第一种方法性能较好。
解决方案 29:
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
解决方案 30:
如果您想要一个易于使用但高度可定制的密钥生成器,请使用key-generator
pypi 包。
这是 GitHub 仓库,您可以在其中找到完整的文档。
你可以自定义它,让它给出你想要的字符串,并且有更多选项。下面是一个例子:
from key_generator.key_generator import generate
custom_key = generate(2, ['-', ':'], 3, 10, type_of_value = 'char', capital = 'mix', seed = 17).get_key()
print(custom_key) # ZLFdHXIUe-ekwJCu
希望这有帮助:)
免责声明:这使用了key-generator
我制作的库。