首页 > 解决方案 > C++ 编码解码

问题描述

// /消息示例:“hello”和移位 1。加密器将每个字母上移 1:h -> i, e -> f, l -> m, l -> m, o -> p . 所以 encrypt("hello") 返回 "ifmmp"。解密函数做相反的事情,所以解密(“ifmmp”)返回“你好”。密码加密器使用表示字母转换的字符串作为加密解密的一种方式。因此,具有密码的加密器:“efyhadwzlvjnktbogrumcpiqxs”加密 a -> e、b -> f、c -> y、d -> h 等等。使用这个加密器,encrypt("hello") 返回 "zannb",并且 decrypt("zannb") 返回 "hello" /

当我运行代码时,我得到了结果:

shift encode result == ifmmpaxpsme
shift encode result == jhoor  ruog
encryptor encode result == c bj aiuw
encryptor encode result == kdedkuerldcqoepujoevlnrewurrjeu
#include <iostream>
#include <string>

using namespace std;

class encryptor
{
public:
    virtual string encode(string original) = 0;
    virtual string decode(string secret) = 0;
};

class shift_encryptor : public encryptor
{
    int shift;

public:
    shift_encryptor(int shift)
    {
        // Your code starts here
        this->shift = shift;
        // Your code ends here
    }

    string encode(string original)
    {
        // Your code starts here 
        char c_original[26] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
        string original_result = "";
        for (int i = 0; i < original.length(); i++)
        {
            int c_index = 0;
            for (int j = 0; j < sizeof(c_original); j++)
            {
                if (original[i] == c_original[j])
                {
                    c_index = j;
                    break;
                }
            }
            int final_index = c_index + this->shift;
            if (final_index > sizeof(c_original) - 1)
                final_index -= sizeof(c_original);
            original_result += c_original[final_index];
        }
        return original_result;
        // Your code ends here
    }

    string decode(string secret)
    {
        // Your code starts here 
        char c_secret[26] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
        string secret_result = "";
        for (int i = 0; i < secret.length(); i++)
        {
            int c_index = 0;
            for (int j = 0; j < sizeof(c_secret); j++)
            {
                if (secret[i] == c_secret[j])
                {
                    c_index = j;
                    break;
                }
            }
            int final_index = c_index - this->shift;
            if (final_index < 0)
                final_index += sizeof(c_secret);
            secret_result += c_secret[final_index];
        }
        return secret_result;
        // Your code ends here
    }
};

class cypher_encryptor : public encryptor
{
    string cypher;
public:
    cypher_encryptor(string cypher)
    {
        // Your code starts here
        this->cypher = cypher;
        // Your code ends here
    }
    string encode(string original)
    {
        // Your code starts here 
        char c_original[26] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
        string original_result = "";
        for (int i = 0; i < original.length(); i++)
        {
            int c_index = 0;
            for (int j = 0; j < this->cypher.length(); j++)
            {
                if (original[i] == this->cypher[j])
                {
                    c_index = j;
                    break;
                }
            }
            original_result += c_original[c_index];
        }
        return original_result;
        // Your code ends here
    }

    string decode(string secret)
    {
        // Your code starts here
        char c_secret[26] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
        string secret_result = "";
        for (int i = 0; i < secret.length(); i++)
        {
            int c_index = 0;
            for (int j = 0; j < sizeof(c_secret); j++)
            {
                if (secret[i] == c_secret[j])
                {
                    c_index = j;
                    break;
                }
            }
            secret_result += this->cypher[c_index];
        }
        return secret_result;
        // Your code ends here
    }
};

//After

int main()
{
    shift_encryptor* shiftTest = new shift_encryptor(1);
    string encodeResult = "";
    string decodeResult = "";

    encodeResult = shiftTest->encode("hello world");
    cout << "shift encode result == " << encodeResult << endl;

    decodeResult = shiftTest->decode("lipps${svph");
    cout << "shift encode result == " << decodeResult << endl;

    // string encodeResult = shiftTest->en

    cypher_encryptor* crypterTest = new cypher_encryptor("efyhadwzlvjnktbogrumcpiqxs");

    encodeResult = crypterTest->encode("heyj fvmpe");
    cout << "encryptor encode result == " << encodeResult << endl;
    decodeResult = crypterTest->decode("me emt shevyp wtjp ihls ftssjkt");
    cout << "encryptor decode result == " << decodeResult << endl;
    return 0;
}

标签: c++

解决方案


您不必费心说明您的预期输出应该是什么。看起来您没有做的一件事是考虑非字母字符。你应该编码所有字符还是只编码字母?如果都是字符,那么您的方法是非常错误的,而不是一种错误。这个答案假设只有字母被编码/解码。

但这里有几个错误:

  • sizeof(c_original)应该是c_original.length()
  • 您的移位算法不使用该shift变量,而是硬编码移位 1,同时省略字母“k”。
  • 您的移位解码似乎只是进一步编码,而不是以另一种方式向后移动(我没有运行它,但是代码太相同了,即,我没有看到我认为应该存在的差异)
  • 您不会在问题陈述中使用相同的消息来测试您的密码类;你怎么知道它是否工作?

正如我的评论所表明的那样,我不认为这是多态性的一个很好的例子。但是布局的一个小改动可以使它成为一个更好的例子。变化实际上是依赖于多态性,在这种情况下,使用一个自由函数来演示使用任何派生自加密对象进行编码/解码。

您的代码是过度思考事物的典型案例。也可能对 ASCII 有一些不了解。我的代码将假定为 ASCII,考虑到您编写的代码,这似乎是安全的。

首先,一些更好的最佳实践。您的构造函数不使用初始化部分。类名以大写字母开头。override覆盖虚函数时使用说明符。using namespace std;是不好的做法。尤其是在像这样的示例中,该示例通常会分布在多个文件中。不要把这个包袱放在你课程的用户身上。额外的输入几乎没有那么糟糕,如果你愿意,你总是可以包含特定的 using 语句。

现在,你的界面。它需要一个虚拟析构函数。在处理多态性时,任何非具体的类仍然需要一个析构函数,而且它必须是虚拟的。如果您至少-Wall -Wextra打开了电源,您应该已经收到警告。如果您不启用警告,则您的行为需要改变。给自己免费的帮助。

class Encryption {
public:
  virtual ~Encryption() = default;  // needed
  virtual void encrypt(std::string& message) = 0;
  virtual void decrypt(std::string& message) = 0;
};

我还稍微更改了函数以通过引用获取字符串。这仅与加密/解密实践有关。加密通信应该意味着加密通信,而不是加密通信副本。

关于字符操作的几个快速说明:

  • 如果我有char letter = 'a';,我可以对那个字符做基本的算术来改变它的值。这意味着++letter;现在使letter保持值'b'。请参阅 ASCII 表。
  • 对于基本的 ASCII 工作,<cctype>将成为您的朋友。

这些注释应该有助于移位加密并简化一些事情:

class ShiftEncryption : public Encryption {
  int m_shift;
public:
  ShiftEncryption(int shift) : Encryption(), m_shift(shift) {}

  void encrypt(std::string& message) override
  {
    for (auto& i : message) {
      if (std::isalpha(i)) {
        i = std::toupper(i);
        i += m_shift;
        if (i > 'Z') {
          i -= 26;
        }
      }
    }
  }

  void decrypt(std::string& message) override
  {
    for (auto& i : message) {
      if (std::isalpha(i)) {
        i -= m_shift;
        if (i < 'A') {
          i += 26;
        }
      }
    }
  }
};

您所要做的就是从字面上添加或减去班次,并在需要时使用快速检查再次环绕。我使用std::isalpha()此代码是因为此代码只关心罗马字母(假设来自您编写的代码)。

我的密码加密:

class CypherEncryption : public Encryption {
  std::string m_cyperAlphabet;
  std::string_view m_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public:
  CypherEncryption(std::string alphabet)
      : m_cyperAlphabet([&alphabet]() {
          std::transform(alphabet.begin(), alphabet.end(), alphabet.begin(),
                         [](char c) { return std::toupper(c); });
          return alphabet;
        }()) {}

  void encrypt(std::string& message) override {
    for (auto& i : message) {
      if (std::isalpha(i)) {
        i = std::toupper(i);
        i = m_cyperAlphabet[m_alphabet.find(i)];
      }
    }
  }

  void decrypt(std::string& message) override {
    for (auto& i : message) {
      if (std::isalpha(i)) {
        i = m_alphabet[m_cyperAlphabet.find(i)];
      }
    }
  }
};

我的代码更小,因为我利用了std::string该类提供的功能。知道一个std::string对象仍然可以被认为是一个字符数组也很有帮助。
注意:作为复制/粘贴预防,我也对构造函数发疯了。

我将在这里花一点时间来解释为什么我将所有内容都大写。首先,如果所有字母大小写相同,事情就会变得更容易。如果我必须分别处理大写和小写字母,这段代码会大很多。其次,这是一个非常小的比较点,可以说简单的替换密码从所有字母都相同的情况下获得了更多的安全性。考虑通过大写字母识别专有名称,这会立即给对手额外的提示。现代数字加密方案直接处理比特,因此在“现实世界”中它不是问题。

现在,我们来看看是什么激发了我最初的评论。您的主要功能不会做任何多态的事情。您使用堆分配的加密完成这些步骤,但实际上您并没有使用多态性。我们将通过编写一个免费函数来演示加密引擎来改变这一点。

void demonstrate(std::string message, Encryption& engine)
{
  std::cout << std::setw(10) << std::left << "Original: " << message << '\n';
  engine.encrypt(message);
  std::cout << std::setw(10) << std::left << "Encoded: " << message << '\n';
  engine.decrypt(message);
  std::cout << std::setw(10) << std::left << "Decoded: " << message << "\n\n";
}

注意第二个参数。它是对 Encryption 的引用,它是我的抽象基类。正是通过对类的指针或引用,我们获得了多态性。

我按值获取消息,以便保留它以main()供重复使用。

现在有了这个函数,主函数被简化了很多:

int main()
{
  std::string firstMessage("Hello World");
  std::string secondMessage("Zipper");

  ShiftEncryption byOne(1);
  ShiftEncryption byTen(10);

  std::cout << "Shift by 1:\n";
  demonstrate(firstMessage, byOne);
  demonstrate(secondMessage, byOne);
  std::cout << "Shift by 10:\n";
  demonstrate(firstMessage, byTen);
  demonstrate(secondMessage, byTen);

  std::cout << "Provided cypher:\n";
  CypherEncryption cypher("efyhadwzlvjnktbogrumcpiqxs");
  demonstrate(firstMessage, cypher);

  std::cout << "'Unknown' cypher:\n";
  std::string alphabet("abcdefghijklmnopqrstuvwxyz");
  std::shuffle(alphabet.begin(), alphabet.end(), std::mt19937(std::random_device{}()));
  CypherEncryption oneTimePad(alphabet);
  demonstrate(firstMessage, oneTimePad);
}

输出:

Shift by 1:
Original: Hello World
Encoded:  IFMMP XPSME
Decoded:  HELLO WORLD

Original: Zipper
Encoded:  AJQQFS
Decoded:  ZIPPER

Shift by 10:
Original: Hello World
Encoded:  ROVVY GYBVN
Decoded:  HELLO WORLD

Original: Zipper
Encoded:  JSZZOB
Decoded:  ZIPPER

Provided cypher:
Original: Hello World
Encoded:  ZANNB IBRNH
Decoded:  HELLO WORLD

'Unknown' cypher:
Original: Hello World
Encoded:  CHLLG AGVLK
Decoded:  HELLO WORLD

请注意,我不需要在堆上分配ShiftEncryptionor CypherEncryption(我什么也没做new)。这个例子根本不需要。每次运行时输出末尾的一次性密码都不同,因为密码密钥是在每次运行时随机生成的。

如果这是一个家庭作业,那么恭喜你,它已经为你完成了。


推荐阅读