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

Hellnar 1247 python string random

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

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

  • 6U1S75
  • 4Z4UKK
  • U911K4

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

Ignacio Vazq.. 2418

答案一行:

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

加密更安全的版本; 请参阅/sf/ask/17360801/:

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

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

  • @jorelli:这不是列表理解; 它是一个生成器表达式. (5认同)
  • @joreilli:我在答案中添加了对此的快速注释,并提供了有关可迭代,列表理解,生成器以及最终yield关键字的更详细答案的链接。 (2认同)

小智.. 527

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

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

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

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

  • 很好的答案.小注意:您将其更改为`string.uppercase`,这可能会导致意外结果,具体取决于区域设置.在涉及编码的情况下,使用`string.ascii_uppercase`(或base62的`string.ascii_letters + string.digits`而不是base36)更安全. (3认同)
  • 是的,`random`的官方标准库已警告:"**警告**:此模块的伪随机生成器不应用于安全目的.如果需要加密,请使用os.urandom()或SystemRandom安全的伪随机数发生器." 这是ref:[random.SystemRandom](https://docs.python.org/2/library/random.html#random.SystemRandom)和[os.urandom](https://docs.python.org/ 2 /库/ os.html#os.urandom) (2认同)
  • @shakthydoss:不.它可以返回"AAA000",这是一个随机字符串,然后是"AAA000",它也是*随机字符串.您必须明确添加唯一性检查. (2认同)

Bijan.. 171

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

  • +1用于思考问题.也许你可以简单解释一下uuid1和uuid4之间的区别. (13认同)
  • uui1:从主机ID,序列号和当前时间生成UUID.uuid4:生成随机UUID. (8认同)
  • 截断UUID是个好主意吗?根据`string_length`的小小,碰撞的概率可能是一个问题. (8认同)
  • 如果你想跳过字符串转换和连字符替换,你可以只调用my_uuid.get_hex()或uuid.uuid4().get_hex(),它将返回从没有连字符的uuid生成的字符串. (6认同)

Anurag Uniya.. 44

更简单,更快但稍微随机的方式是使用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"也会失败. (8认同)
  • 如果random.sample阻止了字符重用,那么乘以字符集的大小会使多次重复_possible_,但它们仍然不那么__然后它们是纯粹的随机选择.如果我们选择长度为6的字符串,并且我们选择'X'作为第一个字符,在选择示例中,获得第二个字符的'X'的几率与获得'X'的几率相同第一个角色.在random.sample实现中,将'X'作为任何后续字符的几率仅为获得第一个字符的几率的5/6. (5认同)
  • 其中一个例子有重复,所以我怀疑他是否希望禁止重复. (3认同)

Savad KP.. 31

import uuid
lowercase_str = uuid.uuid4().hex  

lowercase_str 是一个随机值 'cea8b32e00934aaea8c005a35d85a5c0'

uppercase_str = lowercase_str.upper()

uppercase_str'CEA8B32E00934AAEA8C005A35D85A5C0'

  • `uppercase_str [:N + 1]` (2认同)
  • @Yajo:不,你不想切片十六进制值.与完整的大写字母和数字序列相比,您删除熵.也许base32编码该值(略微减少熵,从36**n到32**n,仍然优于16**n). (2认同)

小智.. 19

更快,更简单,更灵活的方法是使用strgenmodule(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模块的作者.


MSeifert.. 11

从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使用生成器表达式的情况下,列表理解更快!


Gubbi.. 10

基于另一个Stack Overflow答案,大多数轻量级方法来创建随机字符串和随机十六进制数字,比接受的答案更好的版本是:

('%06x' % random.randrange(16**6)).upper()

快多了.


nemesisfixx.. 9

我以为没人回答这个哈哈!但是,嘿,这是我自己的:

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))], "")

  • @CarlSmith,我的解决方案似乎有点矫枉过正,但我​​知道其他更简单的解决方案,并希望找到另一条通向良好答案的途径.没有自由,创造力就处于危险之中,因此我继续发布它. (12认同)
  • 我不会对此投票,但我认为这对于这么简单的任务来说太复杂了.返回表达式是一个怪物.简单比复杂更好. (4认同)

John La Rooy.. 9

如果您需要随机字符串而不是随机字符串,则应将其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`不是伪随机的吗?可能正在使用更好的算法来生成更随机的数字,但它仍然是伪随机的。 (2认同)

Rob.. 7

与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,直到没有剩下

...使用正确的位将随机数加入()生成器的结果

使用Timeit,对于32个字符的字符串,时间是:

[('generate_with_random_choice', 28.92901611328125),
 ('generate_with_randbits', 20.0293550491333)]

...但对于64个字符的字符串,randbits丢失了;)

我可能永远不会在生产代码中使用这种方法,除非我真的不喜欢我的同事.

编辑:更新以适应问题(仅大写和数字),并使用按位运算符&和>>而不是%和//


Carl Smith.. 5

我会这样:

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) )


Mudit Jain.. 5

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


归档时间:

查看次数:

813374 次

最近记录:

1 年,10 月 前