如何在C++中创建随机字母数字字符串?

jm.*_*jm. 164 c++ string random

我想创建一个随机字符串,由字母数字字符组成.我希望能够指定字符串的长度.

我如何在C++中执行此操作?

Ate*_*ral 269

Mehrdad Afshari的回答可以解决问题,但我发现这个简单的任务有点过于冗长.查找表有时可以创造奇迹:

void gen_random(char *s, const int len) {
    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0; i < len; ++i) {
        s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
    }

    s[len] = 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 请使用C++ 11或随机增强,我们现在在2016年 (15认同)
  • 您可能不希望使用带模数的简单rand().请参阅:http://c-faq.com/lib/randrange.html (11认同)
  • 我们需要一种方法来在stackoverflow上下沉过时的答案. (11认同)
  • @Kent:这就是OpenSSL团队所做的,直到有人想通过valgrind来实现他们的代码.;-) (4认同)
  • 我认为`s [len] = 0`这行不正确.如果`s`是一个C字符串(NULL终止),那么该方法的签名就不必具有`len`parameter.Imo,如果你将长度作为参数传递,你假设数组不是C字符串.因此,如果你没有将C字符串传递给函数,则行[s] [len] = 0`可能会破坏事物,因为数组将从0变为len-1.即使你将C字符串传递给函数,行[s] [len] = 0`也是多余的. (4认同)
  • 我不明白为什么人们对 rand() 的使用感到愤怒。这个问题没有暗示需要一个分布良好的发电机。对读者来说,不必要地将简单的事情复杂化是浪费时间/精力! (3认同)
  • 此代码可能很危险,因为通常使用"len"等参数的函数会在其计数中包含终止NULL.但是这个函数实际上将len + 1个字符写入输出字符串.因此你必须小心使用它,因为如果你有`char buffer [16];`你实际上调用`gen_random(buffer,sizeof(buffer) - 1);`要特别注意记住` - 1` (2认同)

Car*_*arl 100

这是我使用C++ 11改编Ates Goral的答案.我在这里添加了lambda,但原则是你可以传入它,从而控制你的字符串包含的字符:

std::string random_string( size_t length )
{
    auto randchar = []() -> char
    {
        const char charset[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[ rand() % max_index ];
    };
    std::string str(length,0);
    std::generate_n( str.begin(), length, randchar );
    return str;
}
Run Code Online (Sandbox Code Playgroud)

下面是将lambda传递给随机字符串函数的示例:http://ideone.com/Ya8EKf

为什么要使用C++ 11

  1. 因为您可以为您感兴趣的字符集生成遵循特定概率分布(或分布组合)的字符串.
  2. 因为它内置了对非确定性随机数的支持
  3. 因为它支持unicode,所以您可以将其更改为国际化版本.

例如:

#include <iostream>
#include <vector>
#include <random>
#include <functional> //for std::function
#include <algorithm>  //for std::generate_n

typedef std::vector<char> char_array;

char_array charset()
{
    //Change this to suit
    return char_array( 
    {'0','1','2','3','4',
    '5','6','7','8','9',
    'A','B','C','D','E','F',
    'G','H','I','J','K',
    'L','M','N','O','P',
    'Q','R','S','T','U',
    'V','W','X','Y','Z',
    'a','b','c','d','e','f',
    'g','h','i','j','k',
    'l','m','n','o','p',
    'q','r','s','t','u',
    'v','w','x','y','z'
    });
};    

// given a function that generates a random character,
// return a string of the requested length
std::string random_string( size_t length, std::function<char(void)> rand_char )
{
    std::string str(length,0);
    std::generate_n( str.begin(), length, rand_char );
    return str;
}

int main()
{
    //0) create the character set.
    //   yes, you can use an array here, 
    //   but a function is cleaner and more flexible
    const auto ch_set = charset();

    //1) create a non-deterministic random number generator      
    std::default_random_engine rng(std::random_device{}());

    //2) create a random number "shaper" that will give
    //   us uniformly distributed indices into the character set
    std::uniform_int_distribution<> dist(0, ch_set.size()-1);

    //3) create a function that ties them together, to get:
    //   a non-deterministic uniform distribution from the 
    //   character set of your choice.
    auto randchar = [ ch_set,&dist,&rng ](){return ch_set[ dist(rng) ];};

    //4) set the length of the string you want and profit!        
    auto length = 5;
    std::cout<<random_string(length,randchar)<<std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

样本输出.

  • 如果您使用的是C++ 11,那么在您的第一个代码片段中不使用`rand()`是不是更好? (8认同)
  • 我认为使用`rand()`不再是正确的.大声喊叫甚至都不统一...... (5认同)

Gal*_*lik 30

我的2p解决方案:

#include <random>
#include <string>

std::string random_string(std::string::size_type length)
{
    static auto& chrs = "0123456789"
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    thread_local static std::mt19937 rg{std::random_device{}()};
    thread_local static std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2);

    std::string s;

    s.reserve(length);

    while(length--)
        s += chrs[pick(rg)];

    return s;
}
Run Code Online (Sandbox Code Playgroud)

  • @Velkan 老实说,`std::default_random_engine` 并不是我推荐的好东西,因为标准不保证其质量、效率或实现之间的可重复性。 (2认同)
  • @RichardWhitehead 不,因为字符数组“chars”包含空终止符 - 将“1”添加到其长度。这意味着有 `sizeof(chrs) - 1` 个有效字符,并且数组索引从 `0` 开始,因此包含范围将是 `[0, sizeof(chrs) - 2]`,因为 `sizeof(chrs) - 2`是最后一个有效字符的索引。 (2认同)

Meh*_*ari 15

 void gen_random(char *s, size_t len) {
     for (size_t i = 0; i < len; ++i) {
         int randomChar = rand()%(26+26+10);
         if (randomChar < 26)
             s[i] = 'a' + randomChar;
         else if (randomChar < 26+26)
             s[i] = 'A' + randomChar - 26;
         else
             s[i] = '0' + randomChar - 26 - 26;
     }
     s[len] = 0;
 }
Run Code Online (Sandbox Code Playgroud)

  • @dmckee:是的,但那些其他字符集是什么?(EBCDIC没有连续的字母). (2认同)
  • 但是,0..9必须是连续的。没有部门号,但是我对此很确定。 (2认同)

nly*_*nly 9

我刚试过这个,它很好用,不需要查找表.rand_alnum()有点强制使用字母数字,但因为它从可能的256个字符中选择了62个,这不是什么大问题.

#include <cstdlib>   // for rand()
#include <cctype>    // for isalnum()   
#include <algorithm> // for back_inserter
#include <string>

char 
rand_alnum()
{
    char c;
    while (!std::isalnum(c = static_cast<char>(std::rand())))
        ;
    return c;
}


std::string 
rand_alnum_str (std::string::size_type sz)
{
    std::string s;
    s.reserve  (sz);
    generate_n (std::back_inserter(s), sz, rand_alnum);
    return s;
}
Run Code Online (Sandbox Code Playgroud)

  • 无法知道此功能需要运行多长时间.这是不太可能的,但严格来说,这可能会无限期地运行. (8认同)

Kon*_*lph 8

我倾向于总是使用结构化的C++方法进行这种初始化.请注意,从根本上说,它与Altan的解决方案没有什么不同.对于C++程序员来说,它只是表达了更好的意图,并且可以更容易地移植到其他数据类型.在这个例子中,C++函数generate_n完全表达了你想要的:

struct rnd_gen {
    rnd_gen(char const* range = "abcdefghijklmnopqrstuvwxyz0123456789")
        : range(range), len(std::strlen(range)) { }

    char operator ()() const {
        return range[static_cast<std::size_t>(std::rand() * (1.0 / (RAND_MAX + 1.0 )) * len)];
    }
private:
    char const* range;
    std::size_t len;
};

std::generate_n(s, len, rnd_gen());
s[len] = '\0';
Run Code Online (Sandbox Code Playgroud)

顺便说一下,请阅读Julienne的文章,了解为什么这个指数的计算比简单的方法(如取模数)更受欢迎.


D D*_*D D 8

我希望这可以帮助别人.

使用C++ 4.9.2 在https://www.codechef.com/ide上测试

#include <iostream>
#include <string>
#include <stdlib.h>     /* srand, rand */

using namespace std;

string RandomString(int len)
{
   srand(time(0));
   string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   string newstr;
   int pos;
   while(newstr.size() != len) {
    pos = ((rand() % (str.size() - 1)));
    newstr += str.substr(pos,1);
   }
   return newstr;
}

int main()
{
   string random_str = RandomString(100);
   cout << "random_str : " << random_str << endl;
}
Run Code Online (Sandbox Code Playgroud)

Output: random_str : DNAT1LAmbJYO0GvVo4LGqYpNcyK3eZ6t0IN3dYpHtRfwheSYipoZOf04gK7OwFIwXg2BHsSBMB84rceaTTCtBC0uZ8JWPdVxKXBd

  • 加1,减1:读者,小心:`RandomString(100)`!;-) (3认同)
  • 这段代码仍然被破坏并且有几个问题。最重要的是,`std::srand()` 应该只在程序开始时调用*一次*(最好是`main()` 中的第一件事)。如果在紧密循环中调用,代码将按原样生成许多相同的“随机”字符串。 (3认同)

Ori*_*ent 7

标准库中最合适的函数是std::sample

#include <algorithm>
#include <iterator>
#include <random>
#include <string>
#include <iostream>

static const char charset[] = 
    "0123456789"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";

template<typename URBG>
std::string gen_string(std::size_t length, URBG&& g) {
    std::string result;
    result.resize(length);
    std::sample(std::cbegin(charset), 
                std::cend(charset),
                std::begin(result),
                std::intptr_t(length),
                std::forward<URBG>(g));
    return result;
}

int main() {
    std::mt19937 g;
    std::cout << gen_string(10, g) << std::endl;
    std::cout << gen_string(10, g) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

随机数生成器的状态应在调用之间保持在函数之外。


gez*_*eza 5

这是一个有趣的单线。需要 ASCII。

void gen_random(char *s, int l) {
    for (int c; c=rand()%62, *s++ = (c+"07="[(c+16)/26])*(l-->0););
}
Run Code Online (Sandbox Code Playgroud)