具有大写字母和数字的随机字符串生成

我想生成一个大小为 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'

该堆栈溢出问题是 “随机字符串 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))

使用random.SystemRandom()代替随机使用 * nix 机器上的 / dev / urandom 和 Windows 中的CryptGenRandom() 。这些是加密安全的 PRNG。在需要安全 PRNG 的应用程序中使用random.choice而不是random.SystemRandom().choice可能会造成灾难性的后果,并且鉴于这个问题的random.SystemRandom().choice ,我敢打赌这个错误已经犯了很多遍了。

如果您使用的是 python3.6 或更高版本,则可以使用MSeifert 的答案中提到的新的secrets模块:

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

一种更简单,更快速但稍微少一些的随机方法是使用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'

一种更快,更轻松,更灵活的方法是使用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(如果不可用,则使用后备),确保表示所需的字符集,使用(或不使用 unicode),确保连续的调用产生唯一的字符串,使用字符串模块字符类之一的子集,等等。这比提供的答案需要更多的代码。概括解决方案的各种尝试均具有局限性,strgen 使用简单的模板语言可以以更简洁和更强大的表达力来解决。

在 PyPI 上:

pip install StringGenerator

披露:我是 strgen 模块的作者。

从 Python 3.6 开始, 如果需要加密方式而不是random模块,则应使用secrets模块(否则,此答案与 @Ignacio Vazquez-Abrams 的答案相同):

from secrets import choice
import string

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

还有一点需要注意:在使用str.join列表理解比使用生成器表达式要快!

根据另一个 Stack Overflow 答案, 创建随机字符串和随机十六进制数的最轻巧的方法,比公认的答案更好的版本是:

('%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))