为了更好地练习我的编码,我正在做一些编码挑战。我正在尝试做一个需要我们做一个ROT13的工作。我的实现是正确的,我只想知道几件事。
空格字符在我的终端屏幕上显示为一个疯狂的字符,我假设这是因为字符编码,尽管我可能错了。另外,我的代码看上去怎么样?
#include <iostream>
#include <string>
using namespace std;
const int LOWER_A = 97;
const int LOWER_M = 109;
const int LOWER_N = 110;
const int LOWER_Z = 122;
const int UPPER_A = 65;
const int UPPER_M = 77;
const int UPPER_N = 78;
const int UPPER_Z = 90;
string rot(string input) {
int inputSize = input.size();
int index = 0;
while(index != inputSize) {
if(input[index] >= LOWER_A && input[index] <= LOWER_M)
input[index] = input[index] + 13;
else if(input[index] >= LOWER_N && input[index] <= LOWER_Z)
input[index] = input[index] - 13;
else if(input[index] >= UPPER_A && input[index] <= UPPER_M)
input[index] = input[index] + 13;
else if(input[index] <= UPPER_N && input[index] <= UPPER_Z)
input[index] = input[index] - 13;
index++;
}
return input;
}
int main() {
string plaintext;
string cypher;
cout << "input: ";
getline(cin,plaintext);
cypher = rot(plaintext);
cout << cypher << endl;
return 0;
}发布于 2012-08-12 00:27:53
一些很小的事情:
字符
您可以不使用常量,而只使用内联字符:
if(input[index] >= 'a' && input[index] <= 'm')但是值得注意的是,文字字符将是char,而不是像常量那样的int (但是不会影响本程序中的任何内容)。
using namespace std;在这样的短程序中是可以的,但正如您暗示您对C++相当陌生一样,我想提一下,这可能是一个坏习惯。特别是,在具有许多不同代码段的大型应用程序中,这可能导致命名冲突。
这个问题可以解决它可能引起的问题。
我可能会打电话给rot,rot13,因为还有其他类型的旋转。这主要是我太挑剔了:)。
空间的
input[index] <= UPPER_N,则这将始终是正确的,因此,第二个条件实际上没有意义。
不管怎么说,我认为正在发生的是,空间字符(和任何在‘N’之下的东西)掉进了这个块,而它不应该是。
空格是ASCII 32,所以它被更改为19,这不是一个可打印的字符。while诉for您的循环似乎非常适合for循环的构造,因此我可以考虑使用以下方法:
for (int inputSize = input.size(), index = 0; index != inputSize; ++index) {
}不过,这可以归结为个人偏好。
的返回类型。
std::string::size()不返回int;它返回一个std::string::size_type (在我见过的每个实现中都是如此)、一个size_t (根据平台和编译器的不同,依次是一个无符号的32位或64位整数)。
无论如何,在使用标准容器(或一般的API)时,除非您有理由使用不同的类型,否则我会尝试使用指定的返回类型。例如:
for (std::string::size_type len = input.size(), idx = 0; idx != len; ++idx) {
//input[idx] = ...;
}我怀疑使用isalpha和家族可以将if-else树简化一点,但这就是我可能实现的算法;
std::string rot13(std::string input) {
for (std::string::size_type len = input.length(), idx = 0; idx != len; ++idx) {
if (input[idx] >= 'a' && input[idx] <= 'm') {
input[idx] = input[index] + 13;
} else if (input[idx] >= 'n' && input[idx] <= 'z') {
input[idx] = input[idx] - 13;
} else if(input[idx] >= 'A' && input[idx] <= 'M') {
input[index] = input[index] + 13;
} else if(input[idx] >= 'N' && input[idx] <= 'Z') {
input[index] = input[index] - 13;
}
}
return input;
}为了稍感兴趣,您还可以使用迭代器实现它。使用迭代器将允许您将其应用于任何实现迭代器的容器(所有标准容器和普通指针)。
template <typename Iter>
void rot13(Iter begin, const Iter& end) {
while (begin != end) {
//Doesn't need to be here, but I'm lazy and don't like
//typing *begin over and over again.
char& c = *begin;
if (c >= 'a' && c <= 'm') {
c += 13;
} else if (c >= 'n' && c <= 'z') {
c -= 13;
} else if (c >= 'A' && c <= 'M') {
c += 13;
} else if (c >= 'N' && c <= 'Z') {
c -= 13;
}
++begin;
}
}请注意,这会修改容器,而不是创建副本:
char str[] = "Hello World";
rot13(str, str + strlen(str));
std::cout << str << std::endl;
rot13(str, str + strlen(str));
std::cout << str << std::endl;将产出:
Uryyb Jbeyq
Hello World当然,您可以将其修改为对副本进行操作。
发布于 2012-08-13 12:33:50
就像我在其他地方说的,尽可能避免循环。这减少了发生溢出错误的可能性.C++提供了范围的算法,最好是使用这些算法。
在你的例子中,那是std::transform。结合C++11 lambda,这使得代码简洁、可读性强。
std::string rot13(std::string text) {
std::transform(
begin(text), end(text), begin(text),
[] (char c) -> char {
if (not std::isalpha(c))
return c;
char const pivot = std::isupper(c) ? 'A' : 'a';
return (c - pivot + 13) % 26 + pivot;
});
return text;
}或者,这个lambda也可以作为一个独立的函数来编写,但是我更喜欢限制作用域,而且由于函数可能不会在其他地方使用,而且相当短,所以它非常适合于lambda。
发布于 2012-08-13 11:04:13
要添加到Corbin的回复中,总是倾向于通过常量引用传递不变的输入参数,这样您就可以避免不必要的对象复制,这往往会导致一些性能上的损失。
std::string rot13(const std::string &input)https://codereview.stackexchange.com/questions/14569
复制相似问题