Respostas:
A resposta de Mehrdad Afshari seria suficiente, mas eu achei isso um pouco detalhado demais para essa tarefa simples. Às vezes, as tabelas de consulta podem fazer maravilhas:
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á incorreta. Se s
for uma string C (terminada em NULL), a assinatura do método não precisaria conter o len
parâmetro. Imo, se você está passando o comprimento como argumento, está assumindo que a matriz não é uma string C. Portanto, se você não estiver passando uma string C para a função, a linha s[len] = 0
poderá quebrar as coisas, pois a matriz passaria de 0 a len-1. E mesmo se você estiver passando uma string C para a função, a linha s[len] = 0
seria redundante.
Aqui está minha adaptação da resposta de Ates Goral usando C ++ 11. Eu adicionei o lambda aqui, mas o princípio é que você pode passá-lo e, assim, controlar quais caracteres sua string contém:
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;
}
Aqui está um exemplo de passagem de um lambda para a função de sequência aleatória: http://ideone.com/Ya8EKf
Por que você usaria C ++ 11 ?
Por exemplo:
#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()
no seu primeiro snippet de código?
rand()
mais. Não é nem uniforme para sair chorando ...
Minha solução 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
vez de mt19937
? O código pareceria mais genérico.
std::default_random_engine
não é algo que eu me recomendo em recomendar, pois o padrão não garante sua qualidade, eficiência ou repetibilidade entre implementações.
sizeof
, mudar o auto&
que std::string
, o que lhe dástd::string::length
std::string
provavelmente era mais lento porque contém um ponteiro interno para seus dados. Isso significaria um indireção extra que uma matriz estática não requer. Também sizeof
nunca pode ser mais lento do que std::string::size
porque é uma constante de tempo de compilação.
std::size
, não apareceu até C++17
e ainda há muitas pessoas apenas codificando, C++11/14
então vou deixar como está por enquanto.
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;
}
Acabei de testar isso, funciona bem e não requer uma tabela de pesquisa. O rand_alnum () meio que expulsa os alfanuméricos, mas como seleciona 62 dos 256 caracteres possíveis, não é grande coisa.
#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;
}
Em vez de fazer um loop manual, prefira usar o algoritmo C ++ apropriado , neste caso std::generate_n
, com um gerador de números aleatórios apropriado :
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;
}
Isso é próximo de algo que eu chamaria de solução "canônica" para esse problema.
Infelizmente, semear corretamente um gerador de números aleatórios C ++ genérico (por exemplo, MT19937) é realmente difícil . O código acima, portanto, usa um modelo de função 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};
}
Isso é complexo e relativamente ineficiente. Felizmente, é usado para inicializar uma thread_local
variável e, portanto, é invocado apenas uma vez por thread.
Finalmente, as inclusões necessárias para o acima são:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
O código acima usa dedução de argumento de modelo de classe e, portanto, requer C ++ 17. Ele pode ser adaptado trivialmente para versões anteriores adicionando os argumentos de modelo necessários.
std::size_t
para std::uniform_int_distribution
? Não consigo ver nenhum outro CTAD
rng
como parâmetro padrão, com algo comotemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, o que seria seguro, mas poderia avisar sobre conversão assinada -> não assinada.
Espero que isso ajude alguém.
Testado em https://www.codechef.com/ide com 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()
, só deve ser chamado uma vez no início do programa (de preferência a primeira coisa a entrar main()
). O código, como está, gerará muitas seqüências "aleatórias" idênticas se chamadas em um loop restrito.
#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
em vez destd::string::value_type[]
Algo ainda mais simples e mais básico, caso você esteja feliz por sua string conter caracteres imprimíveis:
#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
}
Sequência aleatória, cada arquivo executado = sequência 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);
std::generate_n
assumirá o custom_string
comprimento LENGTH_NAME
, mas não o é.
Exemplo para uso do 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;
}
Vamos tornar o acaso conveniente novamente!
Eu criei uma boa solução apenas para cabeçalho C ++ 11. Você pode facilmente adicionar um arquivo de cabeçalho ao seu projeto e, em seguida, adicionar seus testes ou usar seqüências aleatórias para outros fins.
Essa é uma descrição rápida, mas você pode seguir o link para verificar o código completo. A principal parte da solução está na 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
incorpora todas as coisas aleatórias e você pode adicionar suas próprias funcionalidades facilmente. Depois que tivermos Randomer
, é muito fácil gerar strings:
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;
}
Escreva suas sugestões para melhoria abaixo. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Mais uma adaptação, porque a falta de respostas bastaria para minhas necessidades. Antes de tudo, se rand () for usado para gerar números aleatórios, você obterá a mesma saída a cada execução. A semente do gerador de números aleatórios deve ser algum tipo de aleatória. Com o C ++ 11, você pode incluir a biblioteca "random" e inicializar a semente com random_device e mt19937. Essa semente será fornecida pelo sistema operacional e será aleatória o suficiente para nós (por exemplo, relógio). Você pode dar uma gama limites estão incluídos [0,25] no meu caso. E por último, mas não menos importante, eu só precisava de uma sequência aleatória de letras minúsculas, então utilizei a adição de caracteres. Com um conjunto de caracteres, a abordagem não funcionou para mim.
#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;
}
#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;
}
Cuidado ao chamar a função
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 ), sempre resultará na mesma sequência de caracteres. Usar
srand(time(NULL));
antes de chamar a função, embora a função rand () seja sempre propagada com 1 @kjfletch .
Por exemplo:
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';
}