Antworten:
Mehrdad Afsharis Antwort würde den Trick machen, aber ich fand es etwas zu ausführlich für diese einfache Aufgabe. Nachschlagetabellen können manchmal Wunder bewirken:
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
ist falsch. Wenn s
es sich um eine C-Zeichenfolge handelt (NULL-terminiert), muss die Signatur der Methode nicht den len
Parameter enthalten. Imo, wenn Sie die Länge als Argument übergeben, nehmen Sie an, dass das Array keine C-Zeichenfolge ist. Wenn Sie also keine C-Zeichenfolge an die Funktion übergeben, kann die Zeile zu s[len] = 0
Unterbrechungen führen, da das Array von 0 auf len-1 wechselt. Und selbst wenn Sie eine C-Zeichenfolge an die Funktion übergeben, ist die Zeile s[len] = 0
redundant.
Hier ist meine Anpassung der Antwort von Ates Goral mit C ++ 11. Ich habe das Lambda hier hinzugefügt, aber das Prinzip ist, dass Sie es weitergeben und dadurch steuern können, welche Zeichen Ihre Zeichenfolge enthält:
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;
}
Hier ist ein Beispiel für die Übergabe eines Lambda an die Zufallszeichenfolgenfunktion: http://ideone.com/Ya8EKf
Warum sollten Sie C ++ 11 verwenden ?
Beispielsweise:
#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()
in Ihrem ersten Code-Snippet zu verwenden?
rand()
. Es ist nicht einmal Uniform für lautes Schreien ...
Meine 2p-Lösung:
#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
statt mt19937
? Der Code würde allgemeiner aussehen.
std::default_random_engine
kann ich es nicht empfehlen, da der Standard keine Garantie für seine Qualität, Effizienz oder Wiederholbarkeit zwischen Implementierungen gibt.
sizeof
, ändern Sie das auto&
in std::string
, was Ihnenstd::string::length
std::string
wahrscheinlich langsamer ist, da es einen internen Zeiger auf seine Daten enthält. Dies würde eine zusätzliche Indirektion bedeuten, die ein statisches Array nicht benötigt. Auch sizeof
kann nie langsamer als , std::string::size
weil es eine Kompilierung konstant.
std::size
erst erschienen C++17
und es gibt immer noch viele Leute, die nur codieren, C++11/14
also werde ich es so lassen, wie es jetzt ist.
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;
}
Ich habe das gerade getestet, es funktioniert süß und erfordert keine Nachschlagetabelle. rand_alnum () verdrängt alphanumerische Zeichen, aber da 62 von 256 möglichen Zeichen ausgewählt werden, ist dies keine große Sache.
#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;
}
Verwenden Sie in diesem Fall lieber den entsprechenden C ++ - Algorithmusstd::generate_n
mit einem geeigneten Zufallszahlengenerator, als manuell zu schleifen :
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;
}
Dies kommt etwas nahe, das ich als "kanonische" Lösung für dieses Problem bezeichnen würde.
Leider ist es sehr schwierig , einen generischen C ++ - Zufallszahlengenerator (z. B. MT19937) richtig zu setzen . Der obige Code verwendet daher eine Hilfsfunktionsvorlage 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};
}
Dies ist komplex und relativ ineffizient. Zum Glück wird es verwendet, um a zu initialisierenthread_local
Variablen verwendet und daher nur einmal pro Thread aufgerufen.
Schließlich sind die notwendigen Einschlüsse für die oben genannten:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
Der obige Code verwendet die Ableitung von Klassenvorlagenargumenten und erfordert daher C ++ 17. Es kann für frühere Versionen trivial angepasst werden, indem die erforderlichen Vorlagenargumente hinzugefügt werden.
std::size_t
für std::uniform_int_distribution
? Ich kann kein anderes CTAD sehen
rng
als template <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, was sicher wäre, aber vor signierter -> nicht signierter Konvertierung warnen könnte.
Ich hoffe das hilft jemandem.
Getestet unter https://www.codechef.com/ide mit 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()
ist, dass es zu Beginn des Programms nur einmal aufgerufen werden sollte (vorzugsweise als erstes main()
). Der Code generiert so wie er ist viele identische "zufällige" Zeichenfolgen, wenn er in einer engen Schleife aufgerufen wird.
#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
anstelle vonstd::string::value_type[]
Noch einfacher und grundlegender, falls Sie sich freuen, dass Ihre Zeichenfolge druckbare Zeichen enthält:
#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
}
Zufällige Zeichenfolge, jede Ausführungsdatei = andere Zeichenfolge
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
davon ausgegangen custom_string
wird LENGTH_NAME
, dass es eine Länge hat, dies jedoch nicht.
Beispiel für Qt-Verwendung :)
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;
}
Lassen Sie uns zufällig wieder bequem machen!
Ich habe eine schöne Lösung für C ++ 11-Header entwickelt. Sie können Ihrem Projekt problemlos eine Header-Datei hinzufügen und dann Ihre Tests hinzufügen oder zufällige Zeichenfolgen für andere Zwecke verwenden.
Das ist eine kurze Beschreibung, aber Sie können dem Link folgen, um den vollständigen Code zu überprüfen. Der Hauptteil der Lösung ist in der Klasse 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
fasst alle zufälligen Dinge zusammen und Sie können ganz einfach Ihre eigenen Funktionen hinzufügen. Nachdem wir haben Randomer
, ist es sehr einfach, Zeichenfolgen zu generieren:
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;
}
Schreiben Sie unten Ihre Verbesserungsvorschläge. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Noch eine Anpassung, weil keine der Antworten meinen Bedürfnissen genügen würde. Wenn rand () zum Generieren von Zufallszahlen verwendet wird, erhalten Sie bei jedem Lauf die gleiche Ausgabe. Der Startwert für den Zufallszahlengenerator muss eine Art Zufallsgenerator sein. Mit C ++ 11 können Sie eine "zufällige" Bibliothek einbinden und den Startwert mit random_device und mt19937 initialisieren. Dieser Startwert wird vom Betriebssystem bereitgestellt und ist für uns zufällig genug (z. B. Uhr). Sie können einen Bereich angeben, in dem Grenzen [0,25] enthalten sind. Und zu guter Letzt brauchte ich nur zufällige Kleinbuchstaben, also benutzte ich die Zeichenaddition. Mit einem Pool von Charakteren hat der Ansatz für mich nicht geklappt.
#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;
}
Seien Sie vorsichtig, wenn Sie die Funktion aufrufen
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();
}
(angepasst an @Ates Goral ) führt jedes Mal zur gleichen Zeichenfolge. Verwenden
srand(time(NULL));
vor dem Aufruf der Funktion, obwohl die Funktion rand () immer mit 1 @kjfletch gesetzt ist .
Beispielsweise:
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';
}