Ответы:
Мердад Афшари в ответ будет делать трюк, но я нашел это немного слишком многословен для этой простой задачи. Иногда справочные таблицы могут творить чудеса:
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;
}
s[len] = 0
неверна. Если s
это строка C (завершена NULL), то в сигнатуре метода не должно быть len
параметра. Imo, если вы передаете длину в качестве аргумента, вы предполагаете, что массив не является строкой C. Таким образом, если вы не передадите строку C в функцию, строка s[len] = 0
может разбить вещи, так как массив переместится с 0 на len-1. И даже если вы передаете строку C в функцию, строка s[len] = 0
будет избыточной.
Вот моя адаптация ответа Ates Goral с использованием C ++ 11. Я добавил лямбду здесь, но принцип в том, что вы можете передать ее и тем самым контролировать, какие символы содержит ваша строка:
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;
}
Вот пример передачи лямбда-функции в случайную строку: http://ideone.com/Ya8EKf
Почему вы используете C ++ 11 ?
Например:
#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;
}
rand()
в первом фрагменте кода?
rand()
. Это даже не единообразно для громкого
Мое 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;
}
default_random_engine
вместо mt19937
? Код будет выглядеть более общим.
std::default_random_engine
это не то, что я рекомендую, так как стандарт не дает никаких гарантий относительно его качества, эффективности или воспроизводимости между реализациями.
sizeof
, изменить auto&
к std::string
, который дает вамstd::string::length
std::string
вероятно, будет медленнее, потому что он содержит внутренний указатель на свои данные. Это означало бы дополнительное косвенное обращение, которое не требует статический массив. Также sizeof
никогда не может быть медленнее, чем std::string::size
потому, что это постоянная времени компиляции.
std::size
он не появлялся до тех C++17
пор, пока многие люди только пишут код, C++11/14
поэтому я оставлю все как есть.
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;
}
Я только что проверил это, он работает хорошо и не требует таблицы поиска. rand_alnum () сортирует буквенно-цифровые символы, но поскольку он выбирает 62 из 256 возможных символов, это не имеет большого значения.
#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;
}
Вместо того, чтобы вручную зацикливаться, предпочтительнее использовать соответствующий алгоритм C ++ , в данном случае std::generate_n
, с подходящим генератором случайных чисел :
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;
}
Это близко к тому, что я бы назвал «каноническим» решением этой проблемы.
К сожалению, правильно заполнить универсальный генератор случайных чисел C ++ (например, MT19937) действительно сложно . Поэтому в приведенном выше коде используется шаблон вспомогательной функции 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};
}
Это сложно и относительно неэффективно. К счастью, он используется для инициализацииthread_local
переменной и поэтому вызывается только один раз для каждого потока.
Наконец, для этого необходимо включить:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
Приведенный выше код использует вывод аргументов шаблона класса и, следовательно, требует C ++ 17. Его можно легко адаптировать для более ранних версий, добавив необходимые аргументы шаблона.
std::size_t
для std::uniform_int_distribution
? Я не вижу никаких других CTAD
rng
в качестве параметра по умолчанию, с чем-то вродеtemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, что было бы безопасно, но мог бы предупредить о подписанном -> неподписанном преобразовании.
Я надеюсь, что это поможет кому-то.
Протестировано на https://www.codechef.com/ide с 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
RandomString(100)
:! ;-)
std::srand()
должен действительно вызываться только один раз в начале программы (желательно первым делом main()
). Код, как есть, будет генерировать много одинаковых «случайных» строк, если вызывается в тесном цикле.
#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;
}
std::string
вместоstd::string::value_type[]
Что-то еще более простое и более простое на случай, если вы довольны тем, что ваша строка содержит печатные символы:
#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
}
Случайная строка, каждый прогон файла = другая строка
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);
std::generate_n
будет custom_string
иметь длину LENGTH_NAME
, но это не так.
Пример использования Qt :)
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;
}
Давайте снова сделаем случайным удобным!
Я составил хорошее решение C ++ 11 только для заголовков. Вы можете легко добавить один заголовочный файл в свой проект, а затем добавить свои тесты или использовать случайные строки для других целей.
Это краткое описание, но вы можете перейти по ссылке, чтобы проверить полный код. Основная часть решения находится в классе 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
инкапсулирует все случайные вещи, и вы можете легко добавить свои собственные функции к нему. После Randomer
этого очень легко генерировать строки:
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;
}
Напишите ваши предложения по улучшению ниже. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Еще одна адаптация, потому что ни один из ответов не удовлетворит мои потребности. Прежде всего, если rand () используется для генерации случайных чисел, вы получите один и тот же вывод при каждом запуске. Начальное число для генератора случайных чисел должно быть случайным. В C ++ 11 вы можете включить «случайную» библиотеку и инициализировать начальное число с помощью random_device и mt19937. Это начальное число будет предоставлено операционной системой, и оно будет достаточно случайным для нас (например, часы). Можно указать границы диапазона, включенные [0,25] в моем случае. И последнее, но не менее важное: мне нужна была только случайная строка строчных букв, поэтому я использовал добавление символов. При подходе с пулом персонажей у меня не получилось.
#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;
}
//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;
}
Будьте осторожны при вызове функции
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();
}
(адаптировано из @Ates Goral ) каждый раз будет приводить к одной и той же последовательности символов. использование
srand(time(NULL));
перед вызовом функции, хотя функция rand () всегда заполнена 1 @kjfletch .
Например:
void SerialNumberGenerator() {
srand(time(NULL));
for (int i = 0; i < 5; i++) {
cout << gen_random(10) << endl;
}
}
#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] << '\t';
}
return 0;
}
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';
}