Risposte:
La risposta di Mehrdad Afshari avrebbe funzionato, ma l'ho trovata un po 'troppo dettagliata per questo semplice compito. Le tabelle di ricerca a volte possono fare miracoli:
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
non sia corretta. Se s
è una stringa C (NULL terminato) allora la firma del metodo non dovrebbe avere il len
parametro in esso. Imo, se si passa la lunghezza come argomento, si presuppone che l'array non sia una stringa C. Pertanto, se non si passa una stringa C alla funzione, la linea s[len] = 0
potrebbe interrompere le cose, poiché l'array andrebbe da 0 a len-1. E anche se si passa una stringa C alla funzione, la linea s[len] = 0
sarebbe ridondante.
Ecco il mio adattamento della risposta di Ates Goral usando C ++ 11. Ho aggiunto lambda qui, ma il principio è che potresti passarlo e quindi controllare quali caratteri contiene la tua stringa:
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;
}
Ecco un esempio di passaggio di una lambda alla funzione di stringa casuale: http://ideone.com/Ya8EKf
Perché dovresti usare C ++ 11 ?
Per esempio:
#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()
nel tuo primo frammento di codice?
rand()
. Non è nemmeno uniforme per gridare ad alta voce ...
La mia soluzione 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
invece di mt19937
? Il codice sembrerebbe più generico.
std::default_random_engine
non mi sento bene a raccomandare in quanto lo standard non fornisce garanzie sulla sua qualità, efficienza o ripetibilità tra le implementazioni.
sizeof
, cambia auto&
in std::string
, che ti dàstd::string::length
std::string
era probabilmente più lento perché conteneva un puntatore interno ai suoi dati. Ciò significherebbe un ulteriore riferimento indiretto che non è richiesto da un array statico. Inoltre sizeof
non può mai essere più lento di std::string::size
perché è una costante di tempo di compilazione.
std::size
non è apparso fino a quando C++17
e ci sono ancora molte persone che scrivono codice, C++11/14
quindi lo lascerò com'è per ora.
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;
}
Ho appena provato questo, funziona dolcemente e non richiede una tabella di ricerca. rand_alnum () in qualche modo espelle l'alfanumerico, ma poiché seleziona 62 su 256 possibili caratteri non è un grosso problema.
#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;
}
Anziché eseguire manualmente il ciclo, preferisci utilizzare l' algoritmo C ++ appropriato , in questo caso std::generate_n
, con un generatore di numeri casuali appropriato :
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;
}
Questo è vicino a qualcosa che definirei la soluzione "canonica" per questo problema.
Sfortunatamente, seminare correttamente un generatore di numeri casuali C ++ generico (ad esempio MT19937) è davvero difficile . Il codice precedente utilizza pertanto un modello di funzione di supporto, 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};
}
Questo è complesso e relativamente inefficiente. Fortunatamente viene utilizzato per inizializzare una thread_local
variabile e viene quindi invocato una sola volta per thread.
Infine, le disposizioni necessarie per quanto sopra sono:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
Il codice precedente utilizza la deduzione dell'argomento del modello di classe e quindi richiede C ++ 17. Può essere banalmente adattato per le versioni precedenti aggiungendo gli argomenti del modello richiesti.
std::size_t
per std::uniform_int_distribution
? Non riesco a vedere nessun altro
rng
come parametro template <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, il che sarebbe sicuro, ma potrei avvertire della conversione firmata -> non firmata.
Spero che questo aiuti qualcuno.
Testato su https://www.codechef.com/ide con 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()
dovrebbe essere chiamato solo una volta all'inizio del programma (preferibilmente la prima cosa in main()
). Il codice, così com'è, genererà molte stringhe "casuali" identiche se chiamato in un ciclo stretto.
#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
invece distd::string::value_type[]
Qualcosa di ancora più semplice e di base nel caso in cui tu sia felice che la tua stringa contenga caratteri stampabili:
#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
}
Stringa casuale, ogni file eseguito = stringa diversa
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
assumerà la custom_string
lunghezza ha LENGTH_NAME
, ma non lo fa.
Esempio per l'uso di 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;
}
Facciamo di nuovo il caso casuale!
Ho creato una bella soluzione solo per l'intestazione C ++ 11. È possibile aggiungere facilmente un file di intestazione al progetto e quindi aggiungere i test o utilizzare stringhe casuali per altri scopi.
Questa è una breve descrizione, ma puoi seguire il link per controllare il codice completo. La parte principale della soluzione è nella classe 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
incapsula tutte le cose casuali e puoi aggiungere facilmente le tue funzionalità. Dopo che abbiamo Randomer
, è molto facile generare stringhe:
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;
}
Scrivi i tuoi suggerimenti per il miglioramento di seguito. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Ancora un altro adattamento perché nessuna delle risposte basterebbe ai miei bisogni. Prima di tutto se si utilizza rand () per generare numeri casuali, si otterrà lo stesso output ad ogni corsa. Il seme per il generatore di numeri casuali deve essere una sorta di casuale. Con C ++ 11 puoi includere la libreria "random" e puoi inizializzare il seed con random_device e mt19937. Questo seed verrà fornito dal sistema operativo e sarà abbastanza casuale per noi (ad esempio: clock). Puoi dare un intervallo I limiti sono inclusi [0,25] nel mio caso. E, ultimo ma non meno importante, avevo solo bisogno di stringhe casuali di lettere minuscole, quindi ho utilizzato l'aggiunta di caratteri. Con un pool di personaggi l'approccio non ha funzionato per 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;
}
//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;
}
Fare attenzione quando si chiama la funzione
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();
}
(adattato da @Ates Goral ) si tradurrà sempre nella stessa sequenza di caratteri. Uso
srand(time(NULL));
prima di chiamare la funzione, sebbene la funzione rand () sia sempre seminata con 1 @kjfletch .
Per esempio:
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';
}