Come faccio a creare una stringa alfanumerica casuale in C ++?


180

Vorrei creare una stringa casuale, composta da caratteri alfanumerici. Voglio essere in grado di specificare la lunghezza della stringa.

Come posso farlo in C ++?

Risposte:


288

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;
}

5
@Kent: questo è ciò che il team di OpenSSL però, fino a quando qualcuno ha pensato di mettere il proprio codice in valgrind. ;-)
Konrad Rudolph,

11
Probabilmente non vuoi usare un semplice rand () con modulo. Vedi: c-faq.com/lib/randrange.html
Randy Proctor,

5
Penso che la linea s[len] = 0non sia corretta. Se sè una stringa C (NULL terminato) allora la firma del metodo non dovrebbe avere il lenparametro 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] = 0potrebbe 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] = 0sarebbe ridondante.
Felipe,

16
Si prega di utilizzare C ++ 11 o boost random, siamo nel 2016 ora
Nikko

13
Abbiamo bisogno di un modo per affondare le risposte obsolete su StackOverflow.
Velkan,

107

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 ?

  1. Perché puoi produrre stringhe che seguono una certa distribuzione di probabilità (o combinazione di distribuzione) per il set di caratteri che ti interessa.
  2. Perché ha il supporto integrato per numeri casuali non deterministici
  3. Perché supporta unicode, quindi puoi cambiarlo in una versione internazionalizzata.

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;
}

Uscita campione.


Nota che almeno su MSVC 2012, dovrai constare auto randSeed = std :: random_device (), quindi passare randSeed a std :: default_random_engine (). std :: random_device {} () non può essere compilato con questa versione.
NuSkooler,

8
Se usi C ++ 11, non è meglio non utilizzarlo rand()nel tuo primo frammento di codice?
Ehtesh Choudhury,

C ++ 11 ti consente di separare il generatore dal motore, ma ciò che è meglio dipende da quali sono le esigenze della tua applicazione. Questo è il motivo per cui il mio primo frammento usa rand e il secondo no.
Carl

7
Direi che non è più corretto da usare rand(). Non è nemmeno uniforme per gridare ad alta voce ...
Jeremyong,

1
@Carl Penso nella comunità C ++, rand è deprecato e un noto anti-modello per molte ragioni a parte la non uniformità (vedi il discorso di STL "Rand Considered Harmful"). L'astrazione del generatore dalla vista è un concetto C ++ generale che penso sia importante per i professionisti e gli studenti di C ++ per imparare (considera come si ripercuote su std :: chrono, std :: string_view, ecc.).
Jeremyong,

39

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;
}

Forse usare default_random_engineinvece di mt19937? Il codice sembrerebbe più generico.
Velkan,

1
@Velkan Ad essere onesti std::default_random_enginenon mi sento bene a raccomandare in quanto lo standard non fornisce garanzie sulla sua qualità, efficienza o ripetibilità tra le implementazioni.
Galik,

1
Per evitare di usare un array di caratteri letterale e quindi doverlo usare sizeof, cambia auto&in std::string, che ti dàstd::string::length
smac89

Ho sentito che l'accesso a std::stringera 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 sizeofnon può mai essere più lento di std::string::sizeperché è una costante di tempo di compilazione.
Galik,

1
Sì, sì, sarebbe meglio. Tuttavia std::sizenon è apparso fino a quando C++17e ci sono ancora molte persone che scrivono codice, C++11/14quindi lo lascerò com'è per ora.
Galik,

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;
 }

Bello: questo è indipendente dal set di caratteri (almeno per tutti i set di caratteri che hanno un..z, A..Z e 0..9 contenti).
dmckee --- ex gattino moderatore,

2
@dmckee: vero, ma quali altri set di caratteri sono quelli? (EBCDIC non ha lettere contigue).
Greg Hewgill,

1
Um. Immagino di essere sorpreso. Stavo solo facendo il pappagallo di qualcosa che un professore mi ha detto una volta ...
dmckee --- ex gattino moderatore

Un rapido controllo dello standard non mostra tali requisiti di continuità nella sezione 2.2, dove li aspetterei.
David Thornley,

2
0..9 devono essere contigui, però. nessun numero di sezione, ma ne sono sicuro.
Johannes Schaub - litb

10

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;
}

8
Non c'è modo di sapere quanto tempo impiegherà questa funzione. È molto improbabile, ma a rigor di termini, questo potrebbe funzionare indefinitamente.
ctrlc-root

9

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_localvariabile 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.


E 'solo deducendo std::size_tper std::uniform_int_distribution? Non riesco a vedere nessun altro
CTAD

@Caleth Correct. (Perché) ti sorprende?
Konrad Rudolph,

Sono tentato di suggerire di prendere rngcome parametro template <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
predefinito

Mi ci è voluto un secondo per vederlo. Probabilmente stavo sostituendo mentalmente std::uniform_int_distribution<>, il che sarebbe sicuro, ma potrei avvertire della conversione firmata -> non firmata.
Caleth,

6

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


3
Plus 1, Minus 1: Reader, attenzione: RandomString(100)! ;-)
azhrei

2
Questo codice è ancora rotto e presenta diversi problemi. Ancora più importante 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.
Galik,

4

Ecco un divertente one-liner. Ha bisogno di ASCII.

void gen_random(char *s, int l) {
    for (int c; c=rand()%62, *s++ = (c+"07="[(c+16)/26])*(l-->0););
}

2
#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;
}

1
Dovrebbe essere randomDistribution (0, sizeof (allowed_chars) - 2);
Archie,

@Archie perché? Sembra a posto (minIndex, maxIndex) en.cppreference.com/w/cpp/numeric/random/…
Oleg

1
Perché allowed_chars [] contiene anche il carattere '\ 0'.
Archie,

@Archie hai ragione wandbox.org/permlink/pxMJfSbhI4MxLGES Grazie!
Oleg,

Ho aggiornato la soluzione da utilizzare std::stringinvece distd::string::value_type[]
Oleg

1

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
}

1
Suppongo che questa sia la soluzione più semplice e assolutamente adatta per il caso con set di caratteri specificato
VolAnd

1

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);

Questo è un comportamento indefinito, perché std::generate_nassumerà la custom_stringlunghezza ha LENGTH_NAME, ma non lo fa.
Cornstalks,

1

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;
}

Puoi approfondire la tua risposta? Pubblicare solo un pezzo di codice spesso non è molto utile.
Noel Widmer,

1

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_);
    }
};

Randomerincapsula 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


0

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;
}

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;
}


-1

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;
    }
}

-1
#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;
}

-2
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';
}

Sembra quasi lo stesso della risposta più in alto. Non sono sicuro che questa risposta aggiunga alcun valore.
jm.

Sì, fa "srand (time (NULL));" L'indice sarà casuale in ogni iterazione, rendendo la stringa più casuale xD La stringa sarà diversa ogni volta che esegue la funzione ... Anche i caratteri in Syms rappresentano un array singolo, non array di puntatori a stringhe.
Деян Добромиров

1
L'hai provato? srand (time (NULL)) reimposta il generatore casuale allo stesso ciclo e quindi fondamentalmente stamperà una riga dello stesso simbolo.
Öö Tiib,

Ottimo lavoro lì, risolto :)
Деян Добромиров

Funziona sul mio STM32F4 xD
Деян Добромиров
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.