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

问题描述 投票:1182回答:29

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

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

  • 6和1磨损
  • 4Z4UKK
  • U911K4

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

python string random
29个回答
2345
投票

答案一行:

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

我们不会要求创建字符串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'

9
投票

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


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丢失了;)

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

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


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

4
投票

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


4
投票
>>> 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

3
投票

对于那些喜欢功能性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)

如果你不想使用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)

如果你想动态生成序列,只需将join设置为identity。

>>> 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获取下一个完全生成的块,授予此示例似乎有点麻烦,它是......


3
投票

(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  

3
投票

这是对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 + "\n")
oneFile.close()

2
投票
>>> 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'

希望这可以帮助!


2
投票
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

518
投票

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

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

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

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

模块文档还讨论了generate secure tokensbest practices的便捷方法。


2
投票
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,长度)这是一个易于理解的简单算法。它使用列表,因此您可以丢弃不需要的字符。


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

1
投票

有时0(零)和O(字母O)可能会令人困惑。所以我用

import uuid
uuid.uuid4().hex[:6].upper().replace('0','X').replace('O','Y')

0
投票

我想建议你下一个选择:

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]

0
投票

两种方法:

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

第一种方法的表现更好。


0
投票

我已经走了几乎所有的答案,但没有一个看起来更容易。我建议你试试passgen库,它通常用于创建随机密码。

您可以生成随机字符串,包括长度,标点符号,数字,字母和大小写。

这是您案例的代码:

from passgen import passgen
string_length = int(input())
random_string = passgen(length=string_length, punctuation=False, digits=True, letters=True, case='upper')

-1
投票

我发现这更简单,更清洁。

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改为仅做alpha字母数字或仅数字或奇怪的字符或任何你想要的。


-5
投票

您可以使用该代码

var chars = "ABC123";
        var random = new Random();
        var result = new string(
            Enumerable.Repeat(chars, 7) //Change 7 to any number of characters you want in your outcome
                      .Select(s => s[random.Next(s.Length)])
                      .ToArray());

        textBox1.Text = result;

这将随机吐出一个随机的7个字母数字模式,只需将7更改为您想要的任何数字,它将产生许多数字和/或字母。

写这个的另一种方法如下......

var chars = "ABC123";
var stringChars = new char[7]; //Change 7 to any number of characters you want in your outcome
var random = new Random();

for (int i = 0; i < stringChars.Length; i++)
{

stringChars[i] = chars[random.Next(chars.Length)];

}

var finalString = new String(stringChars);

textBox1.Text = finalstring;`

我不确定如何添加限制,例如将它设置为不允许某些数字和/或字母彼此相邻或重复,例如获得“AAA123”,如果有人知道如何限制结果有类似的东西请回复一下


167
投票

Simply use Python's builtin 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

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


30
投票
import uuid
lowercase_str = uuid.uuid4().hex  

lowercase_str是一个像'cea8b32e00934aaea8c005a35d85a5c0'这样的随机值

uppercase_str = lowercase_str.upper()

uppercase_str'CEA8B32E00934AAEA8C005A35D85A5C0'


19
投票

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


10
投票

基于另一个Stack Overflow答案,Most lightweight way to create a random string and a random hexadecimal number,比接受的答案更好的版本是:

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

快多了。


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

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))], "")
© www.soinside.com 2019 - 2024. All rights reserved.