生成比其他字符串大的随机字符串

2024-09-28 23:18:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我不想说太多细节来保持兴趣,所以这里是要点

我正在从数据库中检索8字符字符串(例如:T12C4F6Z)。我需要不断生成8个字符的字符串,但它们必须是唯一的。我不想针对数据库中的所有内容检查字符串是否存在(或每次查询数据库),而是希望将生成限制为大于数据库最大值的任何内容。这将避免碰撞,而且我不需要每次都检查它是否已经存在

我是这样生成字符串的:

alphabet = "0123456789ASD....."
return ''.join(random.choices(alphabet, k=8))

不必循环检查直到新字符串大于最大值,有人知道如何约束生成吗

编辑

我正在努力使这个过程更快。 如果max string=zzzz x,我不想开始生成已经存在的字符串,我的想法是将生成限制为zzz y和zzzzz(因为其他所有内容都会发生冲突)


Tags: 字符串数据库内容returnrandom字符细节choices
3条回答

我喜欢直接使用随机发生器。虽然python的random模块相当不错,但对于其他语言,我遇到了一些问题,例如,在多维空间中生成点时,出现了一些模式

Python支持从基数为36的数字转换为十进制整数。因此,要约束最小值,请将字符串转换为整数并使用userrandint,这很容易支持间隔

将常规的基10整数转换为基36更为复杂,幸运的是,您可以使用从https://code.activestate.com/recipes/65212/剪切的附加库,例如或numpy或活动状态。我只是从一个旧的stackoverflow答案中复制了一个被剪掉的,它被讨论了很多次,并且比ActiveState更紧凑

import string
import random

alphabet = string.digits + string.ascii_uppercase
N = len(alphabet) # 36
MAX1 = int('0000WXYZ', N) + 1
MAX2 = int('ZZZZZZZZ', N)

digs = alphabet

def int2base(x, base):
    digits = []
    while x:
        digits.append(digs[int(x % base)])
        x = int(x / base)
    digits.reverse()
    return ''.join(digits)


r = int2base(random.randint(MAX1, MAX2), N)
if len(r) < 8:  # pad with 0 if needed
    r = rjust(r, '0')

免责声明。python随机数生成器非常好,但它是可能的,因为只有这么多长度为8的唯一字符串。我运行了一些测试,通常需要10万到几百万的时间。即使是一个真正的随机数,你也可以得到任何东西,即使是重复的,只要试着掷硬币或掷骰子几次就行了。请注意,每次更新最大值并不是一个好主意,因为您将用尽列表并很快达到zzzz(可能不到30)。如果您觉得必须100%防止重复,只需构建一个已使用字符串的列表/集合,但这是极不可能的,除非MAX接近zzzz

您可以使用此选项创建唯一的组合:

from itertools import permutations
alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'
permutations(alphabet, 8)

如果您想从所有可能但唯一的条目中随机抽取连续递增的数字,您可以尝试以下方法:

# Get maximum of possible entries:
from functools import reduce
import operator
import math

counts = [8,36]
permuations = int(math.factorial(sum(counts))/reduce(operator.mul, map(math.factorial, counts), 1))

# Generate all possible entries (generator)
from itertools import permutations, islice
alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'
g = permutations(alphabet, 8)

# select a list of random indexes to retrieve
from random import sample, seed
n = 5
seed(101)
lst = sorted(sample(range(0, permuations), 5))

# print 5 values from the original generator based on the random indexes
for i in lst:
    print(next(islice(g, i, None)))

基本上,您创建所有可能的排列(唯一的组合),然后创建一个随机但唯一的索引列表。现在你对指数进行排序,这就是结果总是在增加的原因。然后通过所有可能排列的对应值匹配索引

关于你最近的答复,我是否可以建议你不要太担心碰撞,采取这样的方法:

import random
import string
string_set = set()
# Just digits at chars is 36 possibilities
chars = string.digits + string.ascii_uppercase

# For an 8 character string note that there are 36^8 possibilities
N = 8
gen_str = lambda: ''.join(random.choices(chars, k=N))
# This is about 3000,000,000,000 possibilities

# Let's create some strings
for i in range(10000000):
    chars = gen_str()
    # Python set implemented as hash table so this is O(1). (It doesn't slow down as set grows)
    while chars in string_set:
        #Regenerate random number if collision
        #(This is has a n / (36^6) likelihood of happening where "n" is the number of elements in the set so far). Until you exceed 1 billion elements this is a non-issue
        chars = gen_str()
    print("adding to set: ", chars)
    string_set.add(chars)

这种方法的主要缺点是需要将集合存储在某个地方(pickle并取消pickle),这可能会使数据库中存储的每8个字符的内存使用量增加一倍。如果您的集合对于系统内存来说太大,那么这也将变得不可能。在这种情况下,您可以查看“shelve”模块,该模块提供一个类似dict的数据库对象,您可以通过忽略存储到每个键的值,以与集合基本相同的方式使用该对象

相关问题 更多 >