-1

I am writing a program that uses a substitution cipher. I am trying to replace each char in a string (that the user entered) with a char from another string (the encryption key string). But I am having a bunch of issues doing this with the string.replace() function. It does not replace the the char in the userMessage with the correct char. Although this is not an issue when using a string literal as initialization value for letterReplacement. In addition to this, it somehow temporarily increases the size of the userMessage resulting in the loop running for e.g 5 times in a message 3 char long (no matter how letterReplacement was initialized). I would appreciate any information on why this happens.

#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::string userMessage;

    std::cout << "\nWelcome to my Military Grade* Encryption Software!" << std::endl;
    std::cout << "--------------------------------------------------" << std::endl << std::endl;

    std::cout << "Please enter a secret message you would like to encrypt:\n-" << std::endl;
    getline(std::cin, userMessage);
    std::cout << "-" << std::endl << std::endl;

    const std::vector <std::string> encryptionKey {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZT.,<>!?+- '",
                                                   "ß?pl ,;0=}okm9)]ijN8([uhb7/{zgv6&ctf%xdrys4$e3w|<2Q>1!+#ä-:*GnB"};

    for(size_t i {0}; i < userMessage.size(); ++i)  // Here we encrypt the Message
    {
         char currentCharInUM {userMessage.at(i)};
         size_t currentKeyPosition {encryptionKey.at(0).find(currentCharInUM)}; //finds the position that currentChar is at in first encryptionKey String
         std::cout << "currentKeyPosition: " << currentKeyPosition << " - " << i << std::endl;

         if(currentKeyPosition == std::string::npos) // is letter in userMessage is not in encryptionKey just keep it (skip iteration)
             continue;

         std::string letterReplacement {encryptionKey.at(1).at(currentKeyPosition)};
         userMessage.replace(i,1,letterReplacement);
    }

    std::cout << userMessage;

    return 0;
}
  • please include example input, output and expected output in the question – 463035818_is_not_an_ai Aug 23 '22 at 15:48
  • You'll be glad to hear you don't need anyone's help to figure this out, just a tool you already have: your debugger! This is exactly what a debugger is for. It [runs your program, one line at a time, and shows you what's happening](https://stackoverflow.com/questions/25385173/), this is something that's every C++ developer must know how to do. With your debugger's help you'll able to quickly find all problems in this and all future programs you write, without having to ask anyone for help. Have you tried using your debugger, already? If not, why not? What did your debugger show you? – Sam Varshavchik Aug 23 '22 at 15:52
  • I suspect you submit unicode string with multibyte characters as input to your program. That would explain 5 iterations over "3 chars string". `std::istream` does not handle unicode. – Slava Aug 23 '22 at 16:00
  • 1
    If your intention is to support Unicode, you would be better off using a lookup table rather than two strings. – PaulMcKenzie Aug 23 '22 at 16:03
  • Hello everyone, thanks for your feedback. I will try and do better next time. I am just learning c++ and this is my first post on stackoverflow. – blueapple Aug 23 '22 at 16:52

2 Answers2

3

The first character of 2nd element of the vector encryptionKey 'ß' is equal to 2 bytes. So that when you enter 'a' it returns '├' and when you enter b it returns 'ş'. You can try to put another character instead of 'ß'.

  • Thanks that makes a lot of sense! Am am in the process of learning c++ and did not think of this! Alright just tested it and it now works, thanks a bunch! – blueapple Aug 23 '22 at 16:46
0

If your intention was indeed to store non-ASCII characters, it would have been more advantageous to use a lookup table.

The table could be a std::unordered_map<char, wchar_t> to map the English letters to the encrypted characters:

#include <iostream>
#include <string>
#include <unordered_map>

int main()
{
    // Strings
    const char encryptionKeyA[] =  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZT.,<>!?+- '";
    const wchar_t encryptionKeyW[] = L"ß?pl ,;0=}okm9)]ijN8([uhb7/{zgv6&ctf%xdrys4$e3w|<2Q>1!+#ä-:*GnB";

    // Create the lookup table bassed on the above strings
    std::unordered_map<char, wchar_t> encryptionMap;
    for (int i = 0; i < sizeof(encryptionKeyA); ++i)
       encryptionMap[encryptionKeyA[i]] = encryptionKeyW[i];
    
    // Test
    std::string userMessage = "abcTest";

   // The output string
   std::wstring encryptedString;

   // Now go through each character of the userMessage
   for(auto ch : userMessage)
   {
       // If the character exists, append the associated encrypted character
       auto iter = encryptionMap.find(ch);
       if (iter != encryptionMap.end())
           encryptedString += iter->second;
       else
           encryptedString += L' ';  // Just append a space if it didn't exist
   } 
   std::wcout << encryptedString;
}

Output:

ss?p1 N8

Note that the output is what is displayed if the locale is English. If the terminal/output were set to German, I would assume that the output would be:

ß?p1 N8

since the first character is the "double-s".

Also note that I am assuming that both the original and encrypted character strings are of the same size (in terms of the number of characters) when building the map. If they're not the same size, then the loop to build the map should be adjusted accordingly.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45