Câu trả lời:
Câu trả lời của Mehrdad Afshari sẽ thực hiện mánh khóe, nhưng tôi thấy nó hơi quá dài dòng cho nhiệm vụ đơn giản này. Bảng tra cứu đôi khi có thể làm điều kỳ diệu:
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
là không chính xác. Nếu s
là một chuỗi C (kết thúc NULL) thì chữ ký của phương thức sẽ không phải có len
tham số trong đó. Imo, nếu bạn truyền chiều dài làm đối số, bạn đang giả sử mảng không phải là chuỗi C. Do đó, nếu bạn không truyền chuỗi C cho hàm, dòng s[len] = 0
có thể phá vỡ mọi thứ, vì mảng sẽ đi từ 0 đến len-1. Và ngay cả khi bạn truyền một chuỗi C cho hàm, dòng s[len] = 0
đó sẽ là dự phòng.
Đây là bản phóng tác của tôi về câu trả lời của Ates Goral bằng C ++ 11. Tôi đã thêm lambda vào đây, nhưng nguyên tắc là bạn có thể chuyển nó vào và từ đó kiểm soát các ký tự mà chuỗi của bạn chứa:
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;
}
Dưới đây là một ví dụ về việc chuyển một lambda sang hàm chuỗi ngẫu nhiên: http://ideone.com/Ya8EKf
Tại sao bạn nên sử dụng C ++ 11 ?
Ví dụ:
#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()
trong đoạn mã đầu tiên của bạn?
rand()
nữa. Nó thậm chí không đồng đều để khóc thành tiếng ...
Giải pháp 2p của tôi:
#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
thay vì mt19937
? Các mã sẽ nhìn chung hơn.
std::default_random_engine
nói không phải là điều tôi cảm thấy tốt khi đề xuất vì tiêu chuẩn không đảm bảo về chất lượng, hiệu quả hoặc độ lặp lại giữa các lần thực hiện.
sizeof
, hãy thay đổi auto&
thành std::string
, cung cấp cho bạnstd::string::length
std::string
có khả năng chậm hơn vì nó chứa một con trỏ bên trong dữ liệu của nó. Điều đó có nghĩa là một sự bổ sung thêm mà một mảng tĩnh không yêu cầu. Cũng sizeof
không bao giờ có thể chậm hơn std::string::size
vì nó là hằng số thời gian biên dịch.
std::size
đã không xuất hiện cho đến khi C++17
và vẫn còn rất nhiều người chỉ viết mã để C++11/14
tôi sẽ rời khỏi nó như bây giờ.
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;
}
Tôi vừa thử nghiệm cái này, nó hoạt động rất ngọt và không cần bảng tra cứu. rand_alnum () loại lực lượng ra chữ và số nhưng vì nó chọn 62 trong số 256 ký tự có thể nên nó không phải là vấn đề lớn.
#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;
}
Thay vì lặp theo cách thủ công, hãy sử dụng thuật toán C ++ thích hợp , trong trường hợp này std::generate_n
, với trình tạo số ngẫu nhiên thích hợp :
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;
}
Điều này gần với một cái gì đó mà tôi sẽ gọi là giải pháp canon canonical cho vấn đề này.
Thật không may, việc gieo chính xác một trình tạo số ngẫu nhiên C ++ chung (ví dụ MT19937) thực sự khó khăn . Do đó, đoạn mã trên sử dụng mẫu hàm trợ giúp , 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};
}
Điều này là phức tạp và tương đối không hiệu quả. May mắn thay, nó được sử dụng để khởi tạo mộtthread_local
biến và do đó chỉ được gọi một lần cho mỗi luồng.
Cuối cùng, cần thiết bao gồm những điều trên là:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
Đoạn mã trên sử dụng suy luận đối số mẫu lớp và do đó yêu cầu C ++ 17. Nó có thể được điều chỉnh một cách tầm thường cho các phiên bản trước bằng cách thêm các đối số mẫu được yêu cầu.
std::size_t
cho std::uniform_int_distribution
? Tôi không thể thấy bất kỳ
rng
làm tham số mặc định, với một cái gì đó nhưtemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, điều này sẽ an toàn, nhưng có thể cảnh báo về việc chuyển đổi đã ký -> không dấu.
Tôi hi vọng điêu nay se giup được ai đo.
Đã thử nghiệm tại https://www.codechef.com/ide với 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()
nhất chỉ nên thực sự được gọi một lần khi bắt đầu chương trình (tốt nhất là điều đầu tiên trong main()
). Mã, như vậy, sẽ tạo ra rất nhiều chuỗi "ngẫu nhiên" giống hệt nhau nếu được gọi trong một vòng lặp chặt chẽ.
#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
thay vìstd::string::value_type[]
Một cái gì đó thậm chí còn đơn giản và cơ bản hơn trong trường hợp bạn hài lòng cho chuỗi của mình chứa bất kỳ ký tự có thể in nào:
#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
}
Chuỗi ngẫu nhiên, mỗi tệp chạy = chuỗi khác nhau
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
sẽ giả sử custom_string
có độ dài LENGTH_NAME
, nhưng nó không.
Ví dụ cho việc sử dụng 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;
}
Hãy làm cho ngẫu nhiên thuận tiện một lần nữa!
Tôi đã tạo ra một giải pháp chỉ tiêu đề C ++ 11 tốt đẹp. Bạn có thể dễ dàng thêm một tệp tiêu đề vào dự án của mình và sau đó thêm các thử nghiệm của mình hoặc sử dụng các chuỗi ngẫu nhiên cho các mục đích khác.
Đó là một mô tả nhanh, nhưng bạn có thể theo liên kết để kiểm tra mã đầy đủ. Phần chính của giải pháp là trong lớp 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
bao gồm tất cả các công cụ ngẫu nhiên và bạn có thể thêm chức năng của riêng bạn vào đó một cách dễ dàng. Sau khi chúng ta có Randomer
, việc tạo chuỗi rất dễ dàng:
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;
}
Viết đề xuất của bạn để cải thiện dưới đây. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
Tuy nhiên, một sự thích ứng khác bởi vì không có câu trả lời nào đủ đáp ứng nhu cầu của tôi. Trước hết, nếu rand () được sử dụng để tạo các số ngẫu nhiên, bạn sẽ nhận được cùng một đầu ra ở mỗi lần chạy. Hạt giống cho trình tạo số ngẫu nhiên phải là một số loại ngẫu nhiên. Với C ++ 11, bạn có thể bao gồm thư viện "ngẫu nhiên" và bạn có thể khởi tạo hạt giống với Random_device và mt19937. Hạt giống này sẽ được cung cấp bởi HĐH và nó sẽ đủ ngẫu nhiên cho chúng tôi (ví dụ: đồng hồ). Bạn có thể đưa ra một ranh giới phạm vi được bao gồm [0,25] trong trường hợp của tôi. Và cuối cùng nhưng không kém phần quan trọng, tôi chỉ cần chuỗi ký tự viết thường ngẫu nhiên nên tôi sử dụng phép cộng char. Với một nhóm các nhân vật tiếp cận đã không làm việc cho tôi.
#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;
}
Hãy lưu kho khi gọi hàm
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();
}
(được điều chỉnh bởi @Ates Goral ) nó sẽ dẫn đến cùng một chuỗi ký tự mỗi lần. Sử dụng
srand(time(NULL));
trước khi gọi hàm, mặc dù hàm rand () luôn được gieo bằng 1 @kjfletch .
Ví dụ:
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';
}