¿Cómo creo una cadena alfanumérica aleatoria en C ++?

180

Me gustaría crear una cadena aleatoria, que consta de caracteres alfanuméricos. Quiero poder especificar la longitud de la cadena.

¿Cómo hago esto en C ++?

jm.
fuente

Respuestas:

288

La respuesta de Mehrdad Afshari haría el truco, pero lo encontré demasiado detallado para esta simple tarea. Las tablas de consulta a veces pueden hacer maravillas:

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;
}
Ates Goral
fuente
55
@Kent: eso es lo que el equipo de OpenSSL, hasta que alguien pensó en poner su código en valgrind. ;-)
Konrad Rudolph el
11
Probablemente no quiera usar un simple rand () con módulo. Ver: c-faq.com/lib/randrange.html
Randy Proctor
55
Creo que la línea s[len] = 0es incorrecta. Si se strata de una cadena C (terminada en NULL), la firma del método no tendría que tener el lenparámetro. Imo, si está pasando la longitud como argumento, está asumiendo que la matriz no es una cadena C. Por lo tanto, si no está pasando una cadena C a la función, la línea s[len] = 0podría romper cosas, ya que la matriz pasaría de 0 a len-1. E incluso si está pasando una cadena C a la función, la línea s[len] = 0sería redundante.
Felipe
16
Utilice C ++ 11 o aumente al azar, estamos en 2016 ahora
Nikko
13
Necesitamos una forma de hundir respuestas obsoletas en stackoverflow.
Velkan
107

Aquí está mi adaptación de la respuesta de Ates Goral usando C ++ 11. He agregado el lambda aquí, pero el principio es que puedes pasarlo y así controlar qué caracteres contiene tu cadena:

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

Aquí hay un ejemplo de pasar una lambda a la función de cadena aleatoria: http://ideone.com/Ya8EKf

¿Por qué usarías C ++ 11 ?

  1. Porque puede producir cadenas que sigan una cierta distribución de probabilidad (o combinación de distribución) para el conjunto de caracteres que le interesa.
  2. Porque tiene soporte incorporado para números aleatorios no deterministas
  3. Debido a que es compatible con Unicode, puede cambiar esto a una versión internacionalizada.

Por ejemplo:

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

Salida de muestra.

Carl
fuente
Tenga en cuenta que al menos en MSVC 2012, necesitará const randSeed = std :: random_device (), luego pasar randSeed a std :: default_random_engine (). std :: random_device {} () no puede compilarse con esta versión.
NuSkooler
8
Si está usando C ++ 11, ¿no es mejor no usarlo rand()en su primer fragmento de código?
Ehtesh Choudhury
C ++ 11 le permite separar el generador del motor, pero lo mejor depende de cuáles sean las necesidades de su aplicación. Es por eso que mi primer fragmento usa rand y el segundo no.
Carl
77
Yo diría que ya nunca es correcto usarlo rand(). Ni siquiera es uniforme por el
amor de Dios
1
@Carl Creo que en la comunidad de C ++, rand está en desuso y es un antipatrón bien conocido por muchas razones, aparte de la falta de uniformidad (ver la charla de STL "Rand Considerado Dañino"). La abstracción del generador de la vista es un concepto general de C ++ que creo que es importante para los profesionales y estudiantes de C ++ para aprender (considere cómo se traslada a std :: chrono, std :: string_view, etc.).
jeremyong
39

Mi solución 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;
}
Galik
fuente
Tal vez usar en default_random_enginelugar de mt19937? El código se vería más genérico.
Velkan
1
@Velkan Para ser honesto, std::default_random_engineno es algo que me guste recomendar, ya que el estándar no garantiza su calidad, eficiencia o repetibilidad entre implementaciones.
Galik
1
Para evitar usar un literal de matriz de caracteres y, por lo tanto, tener que usarlo sizeof, cambie el auto&a std::string, que le dastd::string::length
smac89
Sentí que acceder a un std::stringprobablemente sea más lento porque contiene un puntero interno a sus datos. Eso significaría una indirección adicional que una matriz estática no requiere. Además sizeof, nunca puede ser más lento que std::string::sizeporque es una constante de tiempo de compilación.
Galik
1
@Chronial Sí, de hecho, eso sería mejor. Sin embargo std::size, no apareció hasta C++17y todavía hay mucha gente que solo codifica, C++11/14así que lo dejaré como está por ahora.
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;
 }
Mehrdad Afshari
fuente
Agradable: esto es independiente del conjunto de caracteres (al menos para todos los conjuntos de caracteres que tienen a..z, A..Z y 0..9 distintivos).
dmckee --- ex-gatito moderador
2
@dmckee: cierto, pero ¿qué otros conjuntos de caracteres son esos? (EBCDIC no tiene letras contiguas).
Greg Hewgill el
1
Um. Supongo que estoy atrapado. Estaba repitiendo algo que un profesor me dijo una vez ...
dmckee --- ex-gatito moderador
Una comprobación rápida del estándar no muestra tales requisitos de continuidad en la sección 2.2, donde los esperaría.
David Thornley el
2
Sin embargo, se requiere que 0..9 sean contiguos. sin número de sección, pero estoy seguro de esto.
Johannes Schaub - litb
10

Acabo de probar esto, funciona bien y no requiere una tabla de búsqueda. rand_alnum () elimina las alfanuméricas, pero debido a que selecciona 62 de los 256 caracteres posibles, no es gran cosa.

#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;
}
solo
fuente
8
No hay forma de saber cuánto tiempo llevará ejecutar esta función. Es muy poco probable, pero estrictamente hablando, esto podría ejecutarse indefinidamente.
ctrlc-root
9

En lugar de realizar un bucle manual, prefiera usar el algoritmo C ++ apropiado , en este caso std::generate_n, con un generador de números aleatorios adecuado :

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

Esto está cerca de algo que yo llamaría la solución "canónica" para este problema.

Desafortunadamente, sembrar correctamente un generador genérico de números aleatorios C ++ (por ejemplo, MT19937) es realmente difícil . Por lo tanto, el código anterior utiliza una plantilla de función auxiliar 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};
}

Esto es complejo y relativamente ineficiente. Afortunadamente, se usa para inicializar una thread_localvariable y, por lo tanto, solo se invoca una vez por subproceso.

Finalmente, los elementos necesarios para lo anterior son:

#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>

El código anterior utiliza la deducción de argumentos de plantilla de clase y, por lo tanto, requiere C ++ 17. Se puede adaptar trivialmente para versiones anteriores agregando los argumentos de plantilla requeridos.

Konrad Rudolph
fuente
Se acaba deduciendo std::size_tde std::uniform_int_distribution? No puedo ver ninguna otra CTAD
Caleth
@Caleth Correcto. (¿Por qué) te sorprende esto?
Konrad Rudolph
Estoy tentado a sugerir tomarlo rngcomo un parámetro predeterminado, con algo comotemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
Caleth
Me tomó un segundo verlo. Probablemente estaba sustituyendo mentalmente std::uniform_int_distribution<>, lo que sería seguro, pero podría advertir sobre la conversión firmada -> sin firmar.
Caleth
6

Espero que esto ayude a alguien.

Probado en 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

DD
fuente
3
Más 1, Menos 1: Lector, ¡cuidado RandomString(100)! ;-)
azhrei
2
Este código todavía está roto y tiene varios problemas. Lo más importante es std::srand()que solo se debe llamar una vez al comienzo del programa (preferiblemente lo primero main()). El código, tal como está, generará muchas cadenas "aleatorias" idénticas si se llama en un bucle cerrado.
Galik
4

Aquí hay una frase divertida. Necesita ASCII.

void gen_random(char *s, int l) {
    for (int c; c=rand()%62, *s++ = (c+"07="[(c+16)/26])*(l-->0););
}
geza
fuente
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;
}
Oleg
fuente
1
Debería ser randomDistribution (0, sizeof (allowed_chars) - 2);
Archie
@ Archie, ¿por qué? Se ve bien (minIndex, maxIndex) es.cppreference.com/w/cpp/numeric/random/…
Oleg
1
Porque allow_chars [] también contiene el carácter '\ 0'.
Archie
@ Archie tienes razón wandbox.org/permlink/pxMJfSbhI4MxLGES ¡Gracias!
Oleg
Actualicé la solución para usar en std::stringlugar destd::string::value_type[]
Oleg
1

Algo aún más simple y más básico en caso de que esté contento de que su cadena contenga caracteres imprimibles:

#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
}
Nobilis
fuente
1
Supongo que esta es la solución más simple y absolutamente adecuada para el caso con el conjunto de caracteres especificado
VolAnd
1

Cadena aleatoria, cada archivo de ejecución = cadena diferente

        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);
Nehigienix
fuente
Este es un comportamiento indefinido, porque std::generate_nasumirá que custom_stringtiene longitud LENGTH_NAME, pero no lo hace.
Cornstalks
1

Ejemplo de uso 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;
}
Vitalja Alex
fuente
¿Puedes dar más detalles sobre tu respuesta? Publicar solo un fragmento de código a menudo no es muy útil.
Noel Widmer
1

¡Hagamos que el azar sea conveniente nuevamente!

Creé una buena solución de solo encabezado C ++ 11. Puede agregar fácilmente un archivo de encabezado a su proyecto y luego agregar sus pruebas o usar cadenas aleatorias para otros fines.

Esa es una descripción rápida, pero puede seguir el enlace para verificar el código completo. La parte principal de la solución está en la clase 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_);
    }
};

Randomerencapsula todas las cosas al azar y puede agregarle su propia funcionalidad fácilmente. Después de que tenemos Randomer, es muy fácil generar cadenas:

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

Escriba sus sugerencias de mejora a continuación. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad

Gusev Slava
fuente
0

Otra adaptación más porque ninguna de las respuestas sería suficiente para mis necesidades. En primer lugar, si se usa rand () para generar números aleatorios, obtendrá la misma salida en cada ejecución. La semilla para el generador de números aleatorios tiene que ser algún tipo de aleatorio. Con C ++ 11 puede incluir una biblioteca "aleatoria" y puede inicializar la semilla con random_device y mt19937. Esta semilla será suministrada por el sistema operativo y será lo suficientemente aleatoria para nosotros (por ejemplo: reloj). Puede dar un rango límites están incluidos [0,25] en mi caso. Y por último, pero no menos importante, solo necesitaba una cadena aleatoria de letras minúsculas, así que utilicé la adición de caracteres. Con un enfoque de grupo de personajes no funcionó para mí.

#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;
}
Barkin Kaplan
fuente
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;
}
JK25
fuente
-1

Tenga cuidado al llamar a la función

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

(adaptado de @Ates Goral ) dará como resultado la misma secuencia de caracteres cada vez. Utilizar

srand(time(NULL));

antes de llamar a la función, aunque la función rand () siempre se siembra con 1 @kjfletch .

Por ejemplo:

void SerialNumberGenerator() {

    srand(time(NULL));
    for (int i = 0; i < 5; i++) {
        cout << gen_random(10) << endl;
    }
}
Señor oveja
fuente
-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;
}
ras
fuente
-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';
}
Деян Добромиров
fuente
Se ve casi igual que la respuesta mejor clasificada. No estoy seguro de que esta respuesta agregue algún valor.
jm.
Sí, "srand (time (NULL));" El índice será aleatorio en cada iteración, haciendo que su cadena sea más aleatoria xD La cadena será diferente cada vez que ejecute la función ... Además, los caracteres en los símbolos representan un matriz única, no matriz de punteros a cadenas.
Деян Добромиров
1
¿Lo has probado? srand (time (NULL)) restablece el generador aleatorio al mismo durante todo el ciclo, por lo que básicamente imprimirá la fila del mismo símbolo.
Öö Tiib
Buen trabajo allí, arreglado :)
Деян Добромиров
Se ejecuta en mi STM32F4 xD
Деян Добромиров