如何在 C++ 中编写随机大写字符生成器?
How to write a random uppercase char generator in C++?
我对此的看法是
#include <iostream>
int main()
{
for( int i = 0; i < 20; ++i) {
std::cout << (char) ((random() % (int('Z') + 1)) + int('A')) << '\n';
}
}
这似乎很简单。您生成一个数字,该数字介于小于或等于 Z
和大于或等于 A
之间。如果你play with it,你会发现还有其他的字符生成。这是为什么?
你的数学有误。假设 ASCII,(random() % (int('Z') + 1)
可以 return 到 'Z'
的任何内容,包括小写字符、数字、不可打印的字符和其他内容。如果您向其中添加 int('A')
,您会得到一个很大的变化,即获得大写字符之外的结果,甚至超过 127
,因此不再是 ASCII。
您可以简单地使用 'A' + (random() % 26)
。
'Z'
等于90,所以代码:
(random() % (int('Z') + 1)
生成 1 到 90 之间的数字。然后你添加 'A' 即 65,所以你的数字在 66 - 155 范围内。
要修复它,您必须将代码更改为:
std::cout << (char) ((random() % (int('Z' - 'A') + 1)) + int('A')) << '\n';
char c = *("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + rand() % 26);
至少是便携的。请注意 指针算术 在 const char[27]
常量上的使用,该常量 衰减 为表达式中的 const char*
类型。如果以上内容不够随机,请将 rand()
换成 std::random
之外的内容。
使用 <random>
,并且不假设 ASCII,您可以这样做:
const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
constexpr std::size_t output_size = 20;
std::mt19937 rng{std::random_device{}()};
std::uniform_int_distribution<> dis(0, alphabet.size() - 1);
std::string res;
res.reserve(output_size);
std::generate_n(std::back_inserter(res),
output_size,
[&](){ return alphabet[dis()]; });
另一种选择是使用 std::shuffle
。您可以使用它来混合您的字母表并从打乱的字符串中取出您需要的前 N 个字符。那看起来像
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::shuffle(alphabet.begin(), alphabet.end(), std::mt19937{std::random_device{}()});
std::cout << alphabet.substr(20); // N in this case
嗯,我会这样写。它只是对 'A' 到 'Z' 范围内的 RNG 进行采样,然后将其转换为 char。
std::mt19937 rng{ std::random_device{}() };
std::uniform_int_distribution<> dis('A', 'Z');
std::cout << static_cast<char>(dis(rng));
我对此的看法是
#include <iostream>
int main()
{
for( int i = 0; i < 20; ++i) {
std::cout << (char) ((random() % (int('Z') + 1)) + int('A')) << '\n';
}
}
这似乎很简单。您生成一个数字,该数字介于小于或等于 Z
和大于或等于 A
之间。如果你play with it,你会发现还有其他的字符生成。这是为什么?
你的数学有误。假设 ASCII,(random() % (int('Z') + 1)
可以 return 到 'Z'
的任何内容,包括小写字符、数字、不可打印的字符和其他内容。如果您向其中添加 int('A')
,您会得到一个很大的变化,即获得大写字符之外的结果,甚至超过 127
,因此不再是 ASCII。
您可以简单地使用 'A' + (random() % 26)
。
'Z'
等于90,所以代码:
(random() % (int('Z') + 1)
生成 1 到 90 之间的数字。然后你添加 'A' 即 65,所以你的数字在 66 - 155 范围内。 要修复它,您必须将代码更改为:
std::cout << (char) ((random() % (int('Z' - 'A') + 1)) + int('A')) << '\n';
char c = *("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + rand() % 26);
至少是便携的。请注意 指针算术 在 const char[27]
常量上的使用,该常量 衰减 为表达式中的 const char*
类型。如果以上内容不够随机,请将 rand()
换成 std::random
之外的内容。
使用 <random>
,并且不假设 ASCII,您可以这样做:
const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
constexpr std::size_t output_size = 20;
std::mt19937 rng{std::random_device{}()};
std::uniform_int_distribution<> dis(0, alphabet.size() - 1);
std::string res;
res.reserve(output_size);
std::generate_n(std::back_inserter(res),
output_size,
[&](){ return alphabet[dis()]; });
另一种选择是使用 std::shuffle
。您可以使用它来混合您的字母表并从打乱的字符串中取出您需要的前 N 个字符。那看起来像
std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::shuffle(alphabet.begin(), alphabet.end(), std::mt19937{std::random_device{}()});
std::cout << alphabet.substr(20); // N in this case
嗯,我会这样写。它只是对 'A' 到 'Z' 范围内的 RNG 进行采样,然后将其转换为 char。
std::mt19937 rng{ std::random_device{}() };
std::uniform_int_distribution<> dis('A', 'Z');
std::cout << static_cast<char>(dis(rng));