Yanıtlar:
Mehrdad Afshari'nin cevabı hile yapacaktı, ama bu basit görev için biraz fazla ayrıntılı buldum. Arama tabloları bazen harikalar yaratabilir:
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
yanlış. Eğer s
bir C dize (NULL sona erdirilir) o zaman yöntem imzası sahip olmazdı len
içinde parametre. Imo, uzunluğu bağımsız değişken olarak geçiriyorsanız, dizinin bir C dizesi olmadığını varsayarsınız. Bu nedenle, işleve bir C dizesi s[len] = 0
geçirmiyorsanız, dizi 0'dan len-1'e gideceği için çizgi bir şeyleri kırabilir. Ve bir C dizesini işleve geçirseniz bile, çizgi s[len] = 0
gereksiz olur.
İşte Ates Goral'ın cevabını C ++ 11 kullanarak uyarlamam. Lambda'yı buraya ekledim, ancak prensip, onu geçirebilmeniz ve böylece dizenizin hangi karakterleri içerdiğini kontrol edebilmenizdir:
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;
}
Aşağıda, lambda'yı rastgele dize işlevine aktarmaya bir örnek verilmiştir: http://ideone.com/Ya8EKf
Neden C ++ 11 kullanıyorsunuz ?
Örneğin:
#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()
, ilk kod snippet'inizde kullanmak daha iyi değil mi?
rand()
. Yüksek sesle ağlamak için bile üniforma değil ...
2p çözümüm:
#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
yerine mt19937
? Kod daha genel görünecektir.
std::default_random_engine
, standart uygulamalar arasında kalite, verimlilik veya tekrarlanabilirlik konusunda hiçbir garanti vermediği için tavsiye etmekten iyi hissetmiyorum.
sizeof
, değiştirmek auto&
için std::string
size verenstd::string::length
std::string
Verilerine dahili bir işaretçi içerdiğinden, a erişiminin daha yavaş olacağını hissettim . Bu, statik bir dizinin gerektirmediği ekstra bir dolaylama anlamına gelir. Ayrıca derleme zaman sabiti olduğundan sizeof
daha yavaş olamaz std::string::size
.
std::size
o zamana kadar görünmedi C++17
ve hala kodlayan bir sürü insan C++11/14
var, bu yüzden şimdilik olduğu gibi bırakacağım.
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;
}
Sadece test ettim, tatlı çalışıyor ve bir arama tablosu gerektirmiyor. rand_alnum () alfanümerikleri zorlar, ancak olası 256 karakterden 62'sini seçtiği için önemli değildir.
#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;
}
Aksine elle döngü daha uygun kullanmayı tercih C ++ algoritması bu durumda, std::generate_n
bir ile, uygun rasgele sayı üreteci :
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;
}
Bu, bu sorun için “kanonik” çözüm olarak adlandıracağım bir şeye yakın.
Ne yazık ki, genel bir C ++ rasgele sayı üretecini (örneğin MT19937) doğru bir şekilde tohumlamak gerçekten zordur . Yukarıdaki kod bu nedenle bir yardımcı fonksiyon şablonu kullanır 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};
}
Bu karmaşık ve nispeten verimsizdir. Neyse ki,thread_local
değişkeni ve bu nedenle iş parçacığı başına yalnızca bir kez çağrılır.
Son olarak, yukarıdakiler için gerekli kapsamlar şunlardır:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
Yukarıdaki kod sınıf şablonu bağımsız değişken kesinti kullanır ve bu nedenle C ++ 17 gerektirir. Gerekli şablon argümanları eklenerek önceki sürümler için önemsiz bir şekilde uyarlanabilir.
std::size_t
için std::uniform_int_distribution
? Başka bir CTAD göremiyorum
rng
varsayılan bir parametre olarak almayı önermek için template <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, bu güvenli olurdu, ancak imzalı -> imzasız dönüşüm konusunda uyarabilir.
Umarım bu birine yardımcı olur.
Https://www.codechef.com/ide adresinde C ++ 4.9.2 ile test edilmiştir
#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()
yalnızca bir kez çağrılmalıdır (tercihen ilk şey main()
). Kod, olduğu gibi, sıkı bir döngüde çağrılırsa birçok özdeş "rastgele" dizge oluşturur.
#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
yerinestd::string::value_type[]
Dizenizin yazdırılabilir karakterler içermesinden memnun olmanız durumunda daha basit ve daha temel bir şey:
#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
}
Rastgele dize, her çalışma dosyası = farklı dize
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
varsayar , ancak yapmaz. custom_string
LENGTH_NAME
Qt kullanımı için örnek :)
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;
}
Tekrar rastgele uygun hale getirelim!
Güzel bir C ++ 11 üstbilgi çözümü oluşturdum. Projenize kolayca bir başlık dosyası ekleyebilir ve ardından testlerinizi ekleyebilir veya başka amaçlar için rastgele dizeler kullanabilirsiniz.
Bu kısa bir açıklama, ancak tam kodu kontrol etmek için bağlantıyı takip edebilirsiniz. Çözümün ana kısmı Randomer sınıfındadır:
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
tüm rastgele şeyleri enkapsüle eder ve kolayca kendi işlevselliğinizi ekleyebilirsiniz. Elimize geçtikten sonra Randomer
, dizeler oluşturmak çok kolay:
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;
}
İyileştirme önerilerinizi aşağıya yazın. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Yine başka bir adaptasyon, çünkü cevapların olmaması benim ihtiyaçlarım için yeterli olacaktır. Her şeyden önce, rastgele sayılar üretmek için rand () kullanılırsa, her çalıştırmada aynı çıktıyı alırsınız. Rastgele sayı üreteci için tohum bir tür rastgele olmalıdır. C ++ 11 ile "rastgele" kitaplığı ekleyebilir ve tohum rastgele_device ve mt19937 ile başlatabilirsiniz. Bu tohum OS tarafından tedarik edilecek ve bizim için yeterince rasgele olacaktır (örneğin: saat için). Benim durumumda dahil edilen aralık sınırları [0,25] verebilirsiniz. Ve son fakat en az değil, sadece küçük harflerin rastgele dizesine ihtiyacım vardı, bu yüzden char eklemesini kullandım. Karakter havuzu ile yaklaşım benim için çalışmadı.
#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;
}
Fonksiyonu çağırırken eşya olun
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();
}
( @Ates Goral'a uyarlanır ) her seferinde aynı karakter dizisiyle sonuçlanır. kullanım
srand(time(NULL));
işlevi çağırmadan önce, rand () işlevi her zaman 1 @kjfletch ile ekilir .
Örneğin:
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';
}