BooRuleDie
BooRuleDie

Reputation: 55

Cipher Algorithm Problems

Task: This cipher shifts each letter by a number of letters. If the shift takes you past the end of the alphabet, just rotate back to the front of the alphabet.

For example: string = "Abc Def Ghi 999 -*%/&()[]" shift(number that you entered) = 1(Can be any integer)

Program should print like this: Bcd Efg Hij -*%/&()[]

I did this with a void function but once I tried to do same thing with string function it didn't work. It just process first element of string then returns the value. For this particular situation my program prints like "Bbc Def Ghi 999 -*%/&()[]"

Any idea to solve this problem?

#include <iostream>
#include <cmath>

using namespace std;

string Cipher(string password, int shift) {
    char Uppercase[26] = { 'A','B','C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O','P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y','Z' };
    char Lowercase[26] = { 'a','b','c' ,'d' ,'e' ,'f' ,'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o','p' ,'q' ,'r' ,'s' ,'t' ,'u' ,'v' ,'w' ,'x' ,'y','z' };

    for (int i = 0; i < password.length(); i++) {
        for (int k = 0; k < 26; k++) {
            int add = shift + k;

            if (password[i] == Uppercase[k]) {
                for (int i = 0; add > 25; i++) { // controlling add isn't bigger than 25
                    add -= 25;
                }
                password[i] = Uppercase[add]; // converting each letter
            }
            else if (password[i] == Lowercase[k]) {
                for (int i = 0; add > 25; i++) { // controlling add isn't bigger than 25 
                    add -= 25;
                }
                password[i] = Lowercase[add]; //converting each letter
            }
            else {
                k = 25; // if element of string is different from letters, program goes to next element 
            }
        }
    }
    return password;
}

int main() {
    cout << "Please enter an integer different from 0 and multiples of 25: ";
    string password = "Abc def ghi 999 -*%/&()[]";
    int shift;
    cin >> shift;
    cout<< Cipher(password, shift);
    system("pause>0");
}

Upvotes: 0

Views: 350

Answers (2)

A M
A M

Reputation: 15277

Your encryption problem can be solved with one statement by using modern C++.

But because this is somehow advanced, I will give a detailed explanation.


Let us first think, what to do and then, how to implement.


The what:

  1. Only alpha characters shall be converted
  2. None alpha characters shall be output unencrypted (same as input)
  3. In case of encryption, the case of the original letter shall be preserved for the encrypted letter. Meaning, if at position 5 was an uppcase letter, also in the encrypted string the letter in position 5 shall be uppercase
  4. Letters shall be shifted by a specified amount.

The how:

We will first check, it the original letter is an alpha-letter by using the isalpha-function.

So, for the case that it is an alpha letter, we will check, if the letter is in uppercase or in lowercase. Actually, we check only, if it is a uppercase letter.

Because if it is not, then it must be a lowercase letter (because it was definitely a letter, what we did check before, and, if it is not upper, then it is lower case). For this check, we use the isupper-function.

We will then do the shift action. And convert back to a letter, taken the case into account.

We assume ASCII. If we to convert an ASCII letter/character into a 0 based index, we need to do the following:

If we look in the ASCII table, then we see, that and 'A' is equivalent to 65 and so forth. So, to get the 0-based index, we subtract 65 from the letter. Then we have an index value between 0 and 25.

Then we add the shift value. There could of course be an overflow. But, this can be simply corrected by a modulo 26 division.

So: 26->0, 27->1, 28->2 and so on. Rather simple. But, because we want to have later a letter again, we will add 65 to this result.

For lowercase letters, we will do nearly the same, but use 97 for the offset to letter 'a'.

Then, we can put verything in one expresion by using the ternary or conditional-operator.

std::isalpha(c) ? std::isupper(c) ? (c - 65 + shift) % 26 + 65 : (c - 97 + shift) % 26 + 97 : c

This is a short for

    // Check if letter/character is alpha
    if (std::isalpha(c)) {

        // Now check for upper or lower case
        if (std::isupper(c)) {

            // The character is uppercase
            c = (c - 65 + shift) % 26 + 65;
        }
        else {
            // The character is lower case
            c = (c - 97 + shift) % 26 + 97;
        }
    }
    else {
        // The character is not alpha
    }

Same as the one liner, no difference

So, first, check for alpha. If true, check for uppercase, if true, do the conversion for uppcase letter, else for lower case letters. If it was no alpha letter, then leave it unchanged.

All this we will then embed as a Lambda-expresion in a std::transform-statement. Please see here for a description.

The result will be one statement only, for the whole conversion process:

std::transform(password.begin(), password.end(), password.begin(), [shift](const char c)
    {return std::isalpha(c) ? std::isupper(c) ? (c - 65 + shift) % 26 + 65 : (c - 97 + shift) % 26 + 97 : c; });


At the end, we build a small driver program for demo purposes:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main() {

    // Our password
    std::string password = "Abc def ghi 999 -*%/&()[]";

    // Give instruction to the user
    std::cout << "\nPlease enter a postive integer: ";

    // Get number of shifts from user and check, if the value could be read
    if (int shift{}; std::cin >> shift && shift > 0) {

        // Now do the encryption
        std::transform(password.begin(), password.end(), password.begin(), [shift](const char c)
            {return std::isalpha(c) ? std::isupper(c) ? (c - 65 + shift) % 26 + 65 : (c - 97 + shift) % 26 + 97 : c; });

        // Show the result to the user
        std::cout << "\n\nEncrypted passphrase: \t" << password << '\n';
    }
    else std::cerr << "\n\n*** Error: Problem with input!\n\n";
    return 0;
}

And, since the one liner is maybe too advanced, let's use the explicit and more verbose code. Just to be complete:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main() {

    // Our password
    std::string password = "Abc def ghi 999 -*%/&()[]";

    // Give instruction to the user
    std::cout << "\nPlease enter a postive integer: ";

    // Get number of shifts from user and check, if the value could be read
    if (int shift{}; std::cin >> shift && shift > 0) {

        // --------------Can be written in one statement -----------------------
        for (char& c : password) {
            // Check if letter/character is alpha
            if (std::isalpha(c)) {

                // Now check for upper or lower case
                if (std::isupper(c)) {

                    // The character is uppercase
                    c = (c - 65 + shift) % 26 + 65;
                }
                else {
                    // The character is lower case
                    c = (c - 97 + shift) % 26 + 97;
                }
            }
            else {
                // The character is not alpha
            }
            // ------------------------------------------------------------------
        }
        // Show the result to the user
        std::cout << "\n\nEncrypted passphrase: \t" << password << '\n';
    }
    else std::cerr << "\n\n*** Error: Problem with input!\n\n";
    return 0;
}

Upvotes: 1

StefanKssmr
StefanKssmr

Reputation: 1226

Within your k loop you determine the index of the letter in the alphabet. However, when e.g. i=1 then password[1] represents the letter 'b'. Now, starting the k-loop from k==0 where Uppercase[0] and Lowercase[0] represent 'A' and 'a', respectively, you directly end up in the else condition and your k-loop terminates without doing anything (you set k=25 and increment it). Here is a fixed version (note that I also use the modulo operator % to make sure that 0 < add < 26:

#include <iostream>
#include <cmath>

using namespace std;

string Cipher(string password, int shift) {
    char Uppercase[26] = { 'A','B','C' ,'D' ,'E' ,'F' ,'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O','P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,'W' ,'X' ,'Y','Z' };
    char Lowercase[26] = { 'a','b','c' ,'d' ,'e' ,'f' ,'g' ,'h' ,'i' ,'j' ,'k' ,'l' ,'m' ,'n' ,'o','p' ,'q' ,'r' ,'s' ,'t' ,'u' ,'v' ,'w' ,'x' ,'y','z' };

    for (int i = 0; i < password.length(); i++) {
        for (int k = 0; k < 26; k++) {
            int add = (shift + k)%26;
            if (password[i] == Uppercase[k]) {
                password[i] = Uppercase[add]; // converting each letter
                break;
            }
            else if (password[i] == Lowercase[k]) {
                password[i] = Lowercase[add]; //converting each letter
                break;
            }
        }
    }
    return password;
}

int main() {
    cout << "Please enter an integer different from 0 and multiples of 25: ";
    string password = "Abc def ghi 999 -*%/&()[]";
    int shift;
    cin >> shift;
    cout<< Cipher(password, shift);
    system("pause>0");
}

Upvotes: 0

Related Questions