协慌网

登录 贡献 社区

使用大写字母和数字生成随机字符串

我想生成一个大小为 N 的字符串。

它应由数字和大写英文字母组成,例如:

  • 6U1S75
  • 4Z4UKK
  • U911K4

我怎样才能以pythonic方式实现这一目标?

答案

答案一行:

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

甚至更短,从使用random.choices() Python 3.6 开始:

''.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 不会在内存中创建列表,而是一个接一个地生成元素( 这里更多关于此) 。

我们不会要求创建字符串elem 'n',而是要求 Python 创建一个随机字符的'n' 次,从一系列字符中挑选:

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

因此random.choice(chars) for _ in range(size)实际上是创建一个size字符序列。从chars中随机挑选的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'

这个 Stack Overflow 问题是当前 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()而不是随机使用 * nix 机器上的 / dev / urandom 和 Windows 中的CryptGenRandom() 。这些是加密安全的 PRNG。在需要安全 PRNG 的应用程序中使用random.choice而不是random.SystemRandom().choice可能具有潜在的破坏性,并且考虑到这个问题的普及,我敢打赌已经多次犯错了。

如果您使用的是 python3.6 或更高版本,则可以使用新的秘密模块。

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

模块文档还讨论了生成安全令牌最佳实践的便捷方法。

只需使用 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