快速随机字符串

Posted

技术标签:

【中文标题】快速随机字符串【英文标题】:Fast random string 【发布时间】:2018-06-29 13:58:25 【问题描述】:

我正在尝试为程序生成随机字符串 ID(该 ID 仅在程序执行期间必须是唯一的)。我第一次在 Python 中没有任何问题:

class RandomIdGenerator:
    _base_62_chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

    @classmethod
    def get_base_62(cls, length):
        return "".join([random.choice(RandomIdGenerator._base_62_chars) for _ in range(length)])

但由于我需要我的程序使用 C++,所以我试图用它生成相同的字符串。这就是我现在所做的:

void Node::setId()

    QString allow_symbols("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    qsrand(QTime::currentTime().msec());

    for (int i = 0; i < ID_LENGTH; ++i) 
        id_.append(allow_symbols.at(qrand() % (allow_symbols.length())));
    

我有两个主要问题。首先它不使用 C++11(我不知道 Qt 是如何工作的,但我不认为它是 C++11)并且生成的 ID 都是一样的。如果我生成其中四个,我会得到:

"R4NDM1xM"
"R4NDM1xM"
"R4NDM1xM"
"R4NDM1xM"

我尝试使用 C++11 方法,但得到了相同的结果,更糟糕的是,在每次执行时,我得到的结果完全相同:

void Node::setId()

    id_ = "";

    const std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    std::random_device rd;
    std::mt19937 generator(rd());
    std::uniform_int_distribution<int> dist(0, str.size() - 1);

    for (int i = 0; i < Node::ID_LENGTH; ++i)
        id_ += str[dist(generator)];

如何在每次调用方法时生成随机字符串 ID?

【问题讨论】:

在程序开始时只播种一次 伪随机生成器为相同的种子生成几乎不可预测但相同的序列。不要每次都播种。 好的,如果我在开始时只做一次qsrand(QTime::currentTime().msec());,它就可以工作。但是如何使用 C++11 做到这一点呢? 回复:“使用 C++11 执行此操作”——同样的事情。只播一次generator “ID 必须是唯一的” 顺便说一句,您的随机字符串并不保证是唯一的。 【参考方案1】:

除非您需要再次重复“随机”序列,否则随机数生成器只能播种一次。这意味着qsrand(QTime::currentTime().msec()); 应该只在您第一次输入setId() 时被调用。这有点棘手,因为它是一个函数调用,但您可以添加一个静态 bool 变量来跟踪它是否已运行,如果已运行则不要再次调用它。类似的东西

void Node::setId()

    static bool seeded = false;
    QString allow_symbols("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
    if (!seeded) 
    
        qsrand(QTime::currentTime().msec());
        seeded = true;
    

    for (int i = 0; i < ID_LENGTH; ++i) 
        id_.append(allow_symbols.at(qrand() % (allow_symbols.length())));
    

C++11 代码更简单。由于随机生成器是一个对象,因此您可以将其设为静态,并且只会在第一次调用该函数时对其进行初始化。这意味着您的代码变为:

void Node::setId()

    id_ = "";
    id_.reserve(Node::ID_LENGTH); // preallocate storage

    static const std::string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    static std::random_device rd;
    static std::mt19937 generator(rd());
    static std::uniform_int_distribution<int> dist(0, str.size() - 1);

    for (int i = 0; i < Node::ID_LENGTH; ++i)
        id_ += str[dist(generator)];


还应注意,std::random_device 由非确定性源支持。如果您的实现不支持,那么std::random_device 可能会在您每次调用它时产生相同的序列。如果是这种情况,那么您将不得不使用另一个选项来播种 generator,就像使用当前时间一样。

【讨论】:

以上是关于快速随机字符串的主要内容,如果未能解决你的问题,请参考以下文章

golang [用转到快速产生一个随机字符串]

python 生成随机ASCII字符和数字的连续流。有用的快速生成随机文件。

快速返回随机字典项

sql 生成唯一随机数字字符串

随机替换字符串中的单词

关于快速删除字符串