ฉันต้องการสร้างสตริงแบบสุ่มซึ่งประกอบด้วยตัวอักษรและตัวเลข ฉันต้องการที่จะสามารถระบุความยาวของสตริง
ฉันจะทำสิ่งนี้ใน C ++ ได้อย่างไร
ฉันต้องการสร้างสตริงแบบสุ่มซึ่งประกอบด้วยตัวอักษรและตัวเลข ฉันต้องการที่จะสามารถระบุความยาวของสตริง
ฉันจะทำสิ่งนี้ใน C ++ ได้อย่างไร
คำตอบ:
คำตอบของ Mehrdad Afshari จะใช้กลอุบาย แต่ฉันพบว่ามันละเอียดเกินไปสำหรับงานง่าย ๆ นี้ ตารางการค้นหาบางครั้งสามารถทำสิ่งมหัศจรรย์ได้:
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
ไม่ถูกต้อง ถ้าs
เป็นสตริง C (ยกเลิกเป็นโมฆะ) แล้วลายเซ็นของวิธีการจะไม่ต้องมีlen
พารามิเตอร์ในนั้น Imo ถ้าคุณผ่านความยาวเป็นอาร์กิวเมนต์คุณจะถือว่าอาร์เรย์ไม่ใช่สตริง C ดังนั้นหากคุณไม่ได้ส่งผ่านสตริง C ไปยังฟังก์ชั่นบรรทัดs[len] = 0
อาจทำให้บางสิ่งแตกต่างกันได้เนื่องจากอาร์เรย์จะเปลี่ยนจาก 0 เป็น len-1 และแม้ว่าคุณจะผ่านสตริง C ไปยังฟังก์ชันบรรทัดs[len] = 0
ก็จะซ้ำซ้อน
นี่คือการปรับคำตอบของ Ates Goral โดยใช้ C ++ 11 ฉันได้เพิ่มแลมบ์ดาไว้ที่นี่แล้ว แต่หลักการคือคุณสามารถผ่านเข้าไปได้และควบคุมสิ่งที่สตริงของคุณมี:
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;
}
นี่คือตัวอย่างของการส่งแลมบ์ดาไปยังฟังก์ชันสตริงสุ่ม: http://ideone.com/Ya8EKf
ทำไมคุณจะใช้ภาษา C ++ 11 ?
ตัวอย่างเช่น:
#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()
ในข้อมูลโค้ดแรกของคุณ
rand()
อีกต่อไป มันไม่เหมือนกันแม้แต่ในการร้องไห้ออกมาดัง ๆ ...
โซลูชัน 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
แทนmt19937
? รหัสจะมีลักษณะทั่วไปมากขึ้น
std::default_random_engine
ไม่ใช่สิ่งที่ฉันรู้สึกดีเกี่ยวกับการแนะนำเนื่องจากมาตรฐานไม่รับประกันเกี่ยวกับคุณภาพประสิทธิภาพหรือความสามารถในการทำซ้ำระหว่างการนำไปใช้งาน
sizeof
เปลี่ยนauto&
ไปstd::string
ซึ่งจะช่วยให้คุณstd::string::length
std::string
น่าจะช้ากว่าเพราะมีตัวชี้ภายในไปยังข้อมูล นั่นจะหมายถึงการเสริมทางอ้อมที่อาร์เรย์คงที่ไม่ต้องการ ยังsizeof
ไม่สามารถช้ากว่าstd::string::size
เพราะเป็นค่าคงที่เวลารวบรวม
std::size
ยังไม่ปรากฏจนกระทั่งC++17
และยังมีผู้คนจำนวนมากเท่านั้นที่เข้ารหัสC++11/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;
}
ฉันเพิ่งทดสอบมันใช้งานได้ดีและไม่ต้องใช้ตารางการค้นหา rand_alnum () เรียงลำดับกองกำลังออกจากตัวอักษรและตัวเลข แต่เนื่องจากมันเลือก 62 ตัวจาก 256 ตัวอักษรที่เป็นไปได้จึงไม่ใช่เรื่องใหญ่
#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;
}
แทนที่จะวนลูปด้วยตนเองต้องการใช้อัลกอริทึม C ++ที่เหมาะสมในกรณีนี้std::generate_n
ด้วยตัวสร้างตัวเลขสุ่มที่เหมาะสม :
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;
}
นี่ใกล้เคียงกับบางสิ่งที่ฉันเรียกว่า "มาตรฐาน" ของปัญหานี้
น่าเสียดายที่การเพาะเครื่องกำเนิดหมายเลขสุ่ม C ++ อย่างถูกต้อง (เช่น MT19937) นั้นยากมาก รหัสด้านบนจึงใช้เทมเพลตฟังก์ชันตัวช่วย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};
}
สิ่งนี้มีความซับซ้อนและไม่มีประสิทธิภาพ โชคดีที่มันถูกใช้เพื่อเริ่มต้นthread_local
ตัวแปรดังนั้นจึงเรียกใช้เพียงครั้งเดียวต่อเธรด
ในที่สุดสิ่งที่จำเป็นรวมถึงสำหรับข้างต้นคือ:
#include <algorithm>
#include <array>
#include <cstring>
#include <functional>
#include <limits>
#include <random>
#include <string>
รหัสด้านบนใช้การลดอาร์กิวเมนท์ของคลาสเทมเพลตดังนั้นจึงต้องใช้ C ++ 17 สามารถปรับได้เล็กน้อยสำหรับรุ่นก่อนหน้าโดยเพิ่มอาร์กิวเมนต์เทมเพลตที่ต้องการ
std::size_t
เพื่อstd::uniform_int_distribution
? ฉันไม่เห็น CTAD อื่นใด
rng
เป็นพารามิเตอร์ที่ผิดนัดโดยมีบางอย่างเช่นtemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
ซึ่งอาจปลอดภัย แต่อาจเตือนเกี่ยวกับการแปลงที่ไม่ได้ลงชื่อ ->
ฉันหวังว่านี่จะช่วยให้ใครบางคน
ทดสอบที่https://www.codechef.com/ideด้วย 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()
ควรเรียกเพียงครั้งเดียวตอนเริ่มต้นโปรแกรม (โดยเฉพาะอย่างยิ่งสิ่งแรกที่เข้ามาmain()
) รหัสตามที่เป็นอยู่จะสร้างสตริง "สุ่ม" ที่เหมือนกันจำนวนมากหากถูกเรียกในวงวน
นี่คือหนึ่งซับตลก ต้องการ ASCII
void gen_random(char *s, int l) {
for (int c; c=rand()%62, *s++ = (c+"07="[(c+16)/26])*(l-->0););
}
#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
แทนstd::string::value_type[]
มีบางอย่างที่ง่ายและพื้นฐานมากขึ้นในกรณีที่คุณมีความสุขที่จะให้สตริงมีอักขระที่พิมพ์ได้:
#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
}
สตริงสุ่มทุกไฟล์ที่ทำงาน = สตริงที่แตกต่างกัน
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
จะถือว่าcustom_string
มีความยาวLENGTH_NAME
แต่มันไม่ได้
ตัวอย่างการใช้ 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;
}
ฉันสร้าง C ++ 11 ส่วนหัวที่ดีสำหรับการแก้ปัญหาเท่านั้น คุณสามารถเพิ่มไฟล์ส่วนหัวหนึ่งไฟล์ในโครงการของคุณได้อย่างง่ายดายจากนั้นเพิ่มการทดสอบหรือใช้สตริงแบบสุ่มเพื่อวัตถุประสงค์อื่น
นั่นเป็นคำอธิบายอย่างรวดเร็ว แต่คุณสามารถไปที่ลิงก์เพื่อตรวจสอบรหัสเต็ม ส่วนหลักของการแก้ปัญหาอยู่ในระดับ 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
รวบรวมข้อมูลแบบสุ่มทั้งหมดและคุณสามารถเพิ่มฟังก์ชันการทำงานของคุณเองได้อย่างง่ายดาย หลังจากที่เรามีRandomer
มันเป็นเรื่องง่ายมากที่จะสร้างสตริง:
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;
}
เขียนคำแนะนำของคุณเพื่อปรับปรุงด้านล่าง https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
การปรับตัวอีกอย่างหนึ่งเพราะไม่ใช่คำตอบจะเพียงพอต่อความต้องการของฉัน ก่อนอื่นถ้าแรนด์ () ถูกใช้เพื่อสร้างตัวเลขสุ่มคุณจะได้ผลลัพธ์เหมือนกันทุกครั้ง seed สำหรับตัวสร้างจำนวนสุ่มต้องเป็นแบบสุ่ม ด้วย C ++ 11 คุณสามารถรวมไลบรารี "random" และคุณสามารถเริ่มต้นเมล็ดด้วย random_device และ mt19937 เมล็ดพันธุ์นี้จะถูกจัดทำโดยระบบปฏิบัติการและมันจะสุ่มพอสำหรับเรา (เช่น: นาฬิกา) คุณสามารถกำหนดขอบเขตของช่วงได้รวม [0,25] ในกรณีของฉัน และสุดท้าย แต่ไม่ท้ายสุดฉันต้องการตัวอักษรตัวพิมพ์เล็กอย่างเดียวเท่านั้นดังนั้นฉันจึงใช้การเพิ่มอักขระ ด้วยแนวทางของตัวละครที่ไม่ได้ผลสำหรับฉัน
#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;
}
เป็นเครื่องเมื่อเรียกใช้ฟังก์ชัน
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 ) มันจะส่งผลให้มีลำดับอักขระเหมือนกันทุกครั้ง ใช้
srand(time(NULL));
ก่อนที่จะเรียกใช้ฟังก์ชันแม้ว่าฟังก์ชัน rand () จะถูกseedด้วย 1 @kjfletchเสมอ
ตัวอย่างเช่น:
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';
}