I'd like to create a random string, consisting of alpha-numeric characters. I want to be able to be specify the length of the string.
How do I do this in C++?
Answers:
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;
}
Answers:
Mehrdad Afshari's answer would do the trick, but I found it a bit too verbose for this simple task. Look-up tables can sometimes do wonders:
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;
}
Answers:
Rather than manually looping, prefer using the appropriate C++ algorithm, in this case std::generate_n
, with a proper random number generator:
auto generate_random_alphanumeric_string(std::size_t len) -> std::string {
static constexpr auto chars =
'0123456789'
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
'abcdefghijklmnopqrstuvwxyz';
thread_local auto rng = random_generator<>();
auto dist = std::uniform_int_distribution{{}, std::strlen(chars) - 1};
auto result = std::string(len, '0');
std::generate_n(begin(result), len, [&]() { return chars[dist(rng)]; });
return result;
}
This is close to something I would call the “canonical” solution for this problem.
Unfortunately, correctly seeding a generic C++ random number generator (e.g. MT19937) is really hard. The above code therefore uses a helper function template, random_generator
:
template <typename T = std::mt19937>
auto random_generator() -> T {
auto constexpr seed_bits = sizeof(typename T::result_type) * T::state_size;
auto constexpr seed_len = seed_bits / std::numeric_limits<std::seed_seq::result_type>::digits;
auto seed = std::array<std::seed_seq::result_type, seed_len>{};
auto dev = std::random_device{};
std::generate_n(begin(seed), seed_len, std::ref(dev));
auto seed_seq = std::seed_seq(begin(seed), end(seed));
return T{seed_seq};
}
This is complex and relatively inefficient. Luckily it’s used to initialise a thread_local
variable and is therefore only invoked once per thread.
Finally, the necessary includes for the above are:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
The above code uses class template argument deduction and thus requires C++17. It can be trivially adapted for earlier versions by adding the required template arguments.
Answers:
I just tested this, it works sweet and doesn't require a lookup table. rand_alnum() sort of forces out alphanumerics but because it selects 62 out of a possible 256 chars it isn't a big deal.
#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;
}
Answers:
I hope this helps someone.
Tested at https://www.codechef.com/ide with C++ 4.9.2
#include <iostream>
#include <string>
#include <stdlib.h> /* srand, rand */
using namespace std;
string RandomString(int len)
{
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()
{
srand(time(0));
string random_str = RandomString(100);
cout << 'random_str : ' << random_str << endl;
}
Output:
random_str : DNAT1LAmbJYO0GvVo4LGqYpNcyK3eZ6t0IN3dYpHtRfwheSYipoZOf04gK7OwFIwXg2BHsSBMB84rceaTTCtBC0uZ8JWPdVxKXBd
Answers:
Here's my adaptation of Ates Goral's answer using C++11. I've added the lambda in here, but the principle is that you could pass it in and thereby control what characters your string contains:
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;
}
Here is an example of passing in a lambda to the random string function: http://ideone.com/Ya8EKf
Why would you use C++11?
- Because you can produce strings that follow a certain probability distribution (or distribution combination) for the character set you're interested in.
- Because it has built-in support for non-deterministic random numbers
- Because it supports unicode, so you could change this to an internationalized version.
For example:
#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;
}
Answers:
Something even simpler and more basic in case you're happy for your string to contain any printable characters:
#include <time.h> // we'll use time for the seed
#include <string.h> // this is for strcpy
void randomString(int size, char* output) // pass the destination size and the destination itself
{
srand(time(NULL)); // seed with time
char src[size];
size = rand() % size; // this randomises the size (optional)
src[size] = '0'; // start with the end of the string...
// ...and work your way backwards
while(--size > -1)
src[size] = (rand() % 94) + 32; // generate a string ranging from the space character to ~ (tilde)
strcpy(output, src); // store the random string
}
Answers:
My 2p solution:
#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;
}
Answers:
void strGetRandomAlphaNum(char *sStr, unsigned int iLen)
{
char Syms[] = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
unsigned int Ind = 0;
srand(time(NULL) + rand());
while(Ind < iLen)
{
sStr[Ind++] = Syms[rand()%62];
}
sStr[iLen] = '0';
}
Answers:
Be ware when calling the function
string gen_random(const int len) {
static const char alphanum[] = '0123456789'
'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
stringstream ss;
for (int i = 0; i < len; ++i) {
ss << alphanum[rand() % (sizeof(alphanum) - 1)];
}
return ss.str();
}
(adapted of @Ates Goral) it will result in the same character sequence every time. Use
srand(time(NULL));
before calling the function, although the rand() function is always seeded with 1 @kjfletch.
For Example:
void SerialNumberGenerator() {
srand(time(NULL));
for (int i = 0; i < 5; i++) {
cout << gen_random(10) << endl;
}
}
Answers:
Random string, every run file = different string
auto randchar = []() -> char
{
const char charset[] =
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
'abcdefghijklmnopqrstuvwxyz';
const size_t max_index = (sizeof(charset) - 1);
return charset[randomGenerator(0, max_index)];
};
std::string custom_string;
size_t LENGTH_NAME = 6 // length of name
generate_n(custom_string.begin(), LENGTH_NAME, randchar);
Answers:
Here's a funny one-liner. Needs ASCII.
void gen_random(char *s, int l) {
for (int c; c=rand()%62, *s++ = (c+'07='[(c+16)/26])*(l-->0););
}
Answers:
Example for Qt use:)
QString random_string(int length=32, QString allow_symbols=QString('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')) {
QString result;
qsrand(QTime::currentTime().msec());
for (int i = 0; i < length; ++i) {
result.append(allow_symbols.at(qrand() % (allow_symbols.length())));
}
return result;
}
Answers:
#include <iostream>
#include <string>
#include <random>
std::string generateRandomId(size_t length = 0)
{
static const std::string allowed_chars {'123456789BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz'};
static thread_local std::default_random_engine randomEngine(std::random_device{}());
static thread_local std::uniform_int_distribution<int> randomDistribution(0, allowed_chars.size() - 1);
std::string id(length ? length : 32, '0');
for (std::string::value_type& c : id) {
c = allowed_chars[randomDistribution(randomEngine)];
}
return id;
}
int main()
{
std::cout << generateRandomId() << std::endl;
}
Answers:
#include <iostream>
#include <string>
#include <stdlib.h>
int main()
{
int size;
std::cout << 'Enter size : ';
std::cin >> size;
std::string str;
for (int i = 0; i < size; i++)
{
auto d = rand() % 26 + 'a';
str.push_back(d);
}
for (int i = 0; i < size; i++)
{
std::cout << str[i] << ' ';
}
return 0;
}
Answers:
Let's make random convenient again!
I made up a nice C++11 header only solution. You could easily add one header file to your project and then add your tests or use random strings for another purposes.
That's a quick description, but you can follow the link to check full code. The main part of solution is in class Randomer:
class Randomer {
// random seed by default
std::mt19937 gen_;
std::uniform_int_distribution<size_t> dist_;
public:
/* ... some convenience ctors ... */
Randomer(size_t min, size_t max, unsigned int seed = std::random_device{}())
: gen_{seed}, dist_{min, max} {
}
// if you want predictable numbers
void SetSeed(unsigned int seed) {
gen_.seed(seed);
}
size_t operator()() {
return dist_(gen_);
}
};
Randomer
incapsulates all random stuff and you can add your own functionality to it easily. After we have Randomer
, it's very easy to generate strings:
std::string GenerateString(size_t len) {
std::string str;
auto rand_char = [](){ return alphabet[randomer()]; };
std::generate_n(std::back_inserter(str), len, rand_char);
return str;
}
Write your suggestions for improvement below. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Answers:
Yet another adaptation because non of the answers would suffice my needs. First of all if rand() is used to generate random numbers you will get the same output at each run. The seed for random number generator has to be some sort of random. With C++11 you can include 'random' library and you can initialize the seed with random_device and mt19937. This seed will be supplied by the OS and it will be random enough for us(for ex: clock). You can give a range boundaries are included [0,25] in my case. And last but not least I only needed random string of lowercase letters so I utilized char addition. With a pool of characters approach did not work out for me.
#include <random>
void gen_random(char *s, const int len){
static std::random_device rd;
static std::mt19937 mt(rd());
static std::uniform_int_distribution<int> dist(0, 25);
for (int i = 0; i < len; ++i) {
s[i] = 'a' + dist(mt);
}
s[len] = 0;
}
Answers:
//C++ Simple Code
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<char> alphanum =
{'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'
};
string s="";
int len=5;
srand(time(0));
for (int i = 0; i <len; i++) {
int t=alphanum.size()-1;
int idx=rand()%t;
s+= alphanum[idx];
}
cout<<s<<" ";
return 0;
}
No comments:
Post a Comment