Відповіді:
Мердад Афшари в відповідь буде робити трюк, але я знайшов це трохи занадто багатослівний для цієї простої задачі. Оглядові таблиці іноді можуть творити чудеса:
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
був би зайвим.
Ось моя адаптація відповіді Атеса Гораля за допомогою 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';
}