Réponses:
La réponse de Mehrdad Afshari ferait l'affaire, mais je l'ai trouvée un peu trop verbeuse pour cette tâche simple. Les tables de consultation peuvent parfois faire des merveilles:
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
est incorrecte. Si s
est une chaîne C (terminée par NULL), alors la signature de la méthode n'aurait pas à contenir le len
paramètre. Imo, si vous passez la longueur comme argument, vous supposez que le tableau n'est pas une chaîne C. Ainsi, si vous ne passez pas de chaîne C à la fonction, la ligne s[len] = 0
pourrait casser des choses, puisque le tableau passerait de 0 à len-1. Et même si vous passez une chaîne C à la fonction, la ligne s[len] = 0
serait redondante.
Voici mon adaptation de la réponse d'Ates Goral en utilisant C ++ 11. J'ai ajouté le lambda ici, mais le principe est que vous pouvez le transmettre et ainsi contrôler les caractères que contient votre chaîne:
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;
}
Voici un exemple de passage d'un lambda à la fonction de chaîne aléatoire: http://ideone.com/Ya8EKf
Pourquoi utiliseriez-vous C ++ 11 ?
Par exemple:
#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()
dans votre premier extrait de code?
rand()
. Ce n'est même pas uniforme pour pleurer à haute voix ...
Ma solution 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
place de mt19937
? Le code aurait l'air plus générique.
std::default_random_engine
n'est pas quelque chose que je recommande car la norme ne donne aucune garantie sur sa qualité, son efficacité ou sa répétabilité entre les implémentations.
sizeof
, changez le auto&
en std::string
, ce qui vous donnestd::string::length
std::string
était susceptible d'être plus lent car il contient un pointeur interne vers ses données. Cela signifierait une indirection supplémentaire dont un tableau statique n'a pas besoin. Aussi sizeof
ne peut jamais être plus lent que std::string::size
parce qu'il s'agit d'une constante de temps de compilation.
std::size
n'est pas apparu avant C++17
et il y a encore beaucoup de gens qui ne codent que pour C++11/14
donc je vais le laisser tel quel pour le moment.
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;
}
Je viens de tester cela, cela fonctionne bien et ne nécessite pas de table de consultation. rand_alnum () élimine en quelque sorte les caractères alphanumériques, mais comme il sélectionne 62 caractères sur 256 possibles, ce n'est pas un gros problème.
#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;
}
Plutôt que de boucler manuellement, préférez utiliser l' algorithme C ++ approprié , dans ce cas std::generate_n
, avec un générateur de nombres aléatoires approprié :
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'est proche de quelque chose que j'appellerais la solution «canonique» de ce problème.
Malheureusement, semer correctement un générateur de nombres aléatoires C ++ générique (par exemple MT19937) est vraiment difficile . Le code ci - dessus utilise donc un modèle de fonction d'aide, 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};
}
C'est complexe et relativement inefficace. Heureusement, il est utilisé pour initialiser une thread_local
variable et n'est donc appelé qu'une seule fois par thread.
Enfin, les éléments nécessaires pour ce qui précède sont:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
Le code ci-dessus utilise la déduction des arguments de modèle de classe et nécessite donc C ++ 17. Il peut être facilement adapté pour les versions antérieures en ajoutant les arguments de modèle requis.
std::size_t
pour std::uniform_int_distribution
? Je ne vois aucun autre CTAD
rng
comme paramètre par défaut, avec quelque chose commetemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, ce qui serait sûr, mais pourrais avertir d'une conversion signée -> non signée.
J'espère que ça aidera quelqu'un.
Testé sur https://www.codechef.com/ide avec 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()
ne doit être appelé qu'une seule fois au début du programme (de préférence la première chose main()
). Le code, tel quel, générera beaucoup de chaînes "aléatoires" identiques s'il est appelé dans une boucle serrée.
#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
place destd::string::value_type[]
Quelque chose d'encore plus simple et plus basique au cas où vous seriez satisfait que votre chaîne contienne des caractères imprimables:
#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
}
Chaîne aléatoire, chaque fichier d'exécution = chaîne différente
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
il supposera que la custom_string
longueur a LENGTH_NAME
, mais ce n'est pas le cas.
Exemple d'utilisation de 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;
}
Rendons à nouveau le hasard pratique!
J'ai créé une belle solution d'en-tête C ++ 11 uniquement. Vous pouvez facilement ajouter un fichier d'en-tête à votre projet, puis ajouter vos tests ou utiliser des chaînes aléatoires à d'autres fins.
C'est une description rapide, mais vous pouvez suivre le lien pour vérifier le code complet. La partie principale de la solution est dans la 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
incapsule tous les éléments aléatoires et vous pouvez y ajouter facilement vos propres fonctionnalités. Une fois que nous l'avons fait Randomer
, il est très facile de générer des chaînes:
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;
}
Écrivez vos suggestions d'amélioration ci-dessous. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Encore une autre adaptation car aucune des réponses ne suffirait à mes besoins. Tout d'abord, si rand () est utilisé pour générer des nombres aléatoires, vous obtiendrez la même sortie à chaque exécution. La graine du générateur de nombres aléatoires doit être une sorte d'aléatoire. Avec C ++ 11, vous pouvez inclure une bibliothèque "random" et vous pouvez initialiser la graine avec random_device et mt19937. Cette graine sera fournie par l'OS et elle sera assez aléatoire pour nous (par exemple: horloge). Vous pouvez donner une plage de limites sont incluses [0,25] dans mon cas. Et le dernier mais non le moindre, je n'avais besoin que d'une chaîne aléatoire de lettres minuscules, donc j'ai utilisé l'ajout de caractères. Avec une approche de groupe de personnages n'a pas fonctionné pour moi.
#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;
}
Soyez vigilant lors de l'appel de la fonction
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();
}
(adapté de @Ates Goral ) il en résultera à chaque fois la même séquence de caractères. Utilisation
srand(time(NULL));
avant d'appeler la fonction, bien que la fonction rand () soit toujours amorcée avec 1 @kjfletch .
Par exemple:
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';
}