首页
学习
活动
专区
圈层
工具
发布

ROT13实现
EN

Code Review用户
提问于 2012-08-11 23:07:03
回答 3查看 15.2K关注 0票数 4

为了更好地练习我的编码,我正在做一些编码挑战。我正在尝试做一个需要我们做一个ROT13的工作。我的实现是正确的,我只想知道几件事。

空格字符在我的终端屏幕上显示为一个疯狂的字符,我假设这是因为字符编码,尽管我可能错了。另外,我的代码看上去怎么样?

代码语言:javascript
复制
#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;
}
EN

回答 3

Code Review用户

回答已采纳

发布于 2012-08-12 00:27:53

一些很小的事情:

字符

常量

您可以不使用常量,而只使用内联字符:

代码语言:javascript
复制
if(input[index] >= 'a' && input[index] <= 'm')

但是值得注意的是,文字字符将是char,而不是像常量那样的int (但是不会影响本程序中的任何内容)。

using namespace std;

在这样的短程序中是可以的,但正如您暗示您对C++相当陌生一样,我想提一下,这可能是一个坏习惯。特别是,在具有许多不同代码段的大型应用程序中,这可能导致命名冲突。

这个问题可以解决它可能引起的问题。

命名

我可能会打电话给rotrot13,因为还有其他类型的旋转。这主要是我太挑剔了:)。

空间的

奇异性这个空格字符在我的终端屏幕上显示为一个疯狂的角色,我假设这是因为字符编码,尽管我可能错了。 rot13传统上只对alpha字符(A和A)进行操作,因此您的空格字符不应该更改。 我相信你的程序里面有个错误: else if(input[index] <= UPPER_N && input[index] <= UPPER_Z) 如果这不是一个bug,您应该知道,如果是input[index] <= UPPER_N,则这将始终是正确的,因此,第二个条件实际上没有意义。 不管怎么说,我认为正在发生的是,空间字符(和任何在‘N’之下的东西)掉进了这个块,而它不应该是。 空格是ASCII 32,所以它被更改为19,这不是一个可打印的字符。

whilefor

您的循环似乎非常适合for循环的构造,因此我可以考虑使用以下方法:

代码语言:javascript
复制
for (int inputSize = input.size(), index = 0; index != inputSize; ++index) {

}

不过,这可以归结为个人偏好。

通常应该尝试匹配方法

的返回类型。

std::string::size()不返回int;它返回一个std::string::size_type (在我见过的每个实现中都是如此)、一个size_t (根据平台和编译器的不同,依次是一个无符号的32位或64位整数)。

无论如何,在使用标准容器(或一般的API)时,除非您有理由使用不同的类型,否则我会尝试使用指定的返回类型。例如:

代码语言:javascript
复制
for (std::string::size_type len = input.size(), idx = 0; idx != len; ++idx) {
    //input[idx] = ...;
}

A潜在的实现

我怀疑使用isalpha和家族可以将if-else树简化一点,但这就是我可能实现的算法;

代码语言:javascript
复制
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;

}

为了稍感兴趣,您还可以使用迭代器实现它。使用迭代器将允许您将其应用于任何实现迭代器的容器(所有标准容器和普通指针)。

代码语言:javascript
复制
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;

    }

}

请注意,这会修改容器,而不是创建副本:

代码语言:javascript
复制
char str[] = "Hello World";
rot13(str, str + strlen(str));
std::cout << str << std::endl;
rot13(str, str + strlen(str));
std::cout << str << std::endl;

将产出:

代码语言:javascript
复制
Uryyb Jbeyq
Hello World

当然,您可以将其修改为对副本进行操作。

票数 6
EN

Code Review用户

发布于 2012-08-13 12:33:50

就像我在其他地方说的,尽可能避免循环。这减少了发生溢出错误的可能性.C++提供了范围的算法,最好是使用这些算法。

在你的例子中,那是std::transform。结合C++11 lambda,这使得代码简洁、可读性强。

代码语言:javascript
复制
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。

票数 4
EN

Code Review用户

发布于 2012-08-13 11:04:13

要添加到Corbin的回复中,总是倾向于通过常量引用传递不变的输入参数,这样您就可以避免不必要的对象复制,这往往会导致一些性能上的损失。

代码语言:javascript
复制
std::string rot13(const std::string &input)
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/14569

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档