简体   繁体   中英

Caesar Cipher C# - How to work with uppercase and lowercase letters

I am creating a Caesar Cipher and I'm trying to figure out how to make it work with both uppercase and lowercase letters. For Example if I type in "Hello World" I want it to encrypt in the same format, "Ifmmp Xpsme.

using System;

namespace CaesarCipher1
{
    class Program
    {
        static string Encrypt(string value, int shift)
        {
            shift %= 26;
            char[] alphabet = value.ToCharArray();
            for (int i = 0; i < alphabet.Length; i++)
            {
                char letter = alphabet[i];
                if (letter == ' ')
                    continue;

                letter = (char)(letter + shift);
                if (letter > 'z')
                {
                    letter = (char)(letter - 26);
                }
                else if (letter < 'a')
                {
                    letter = (char)(letter + 26);
                }

                // Store.
                alphabet[i] = letter;
            }
            return new string(alphabet);
        }
        static string Decrypt(string value, int shift)
        {
            return Encrypt(value, 26 - shift);
        }

        static void Main(string[] args)
        {
            bool Continue = true;

            Console.WriteLine("      Ceasar Cipher");
            Console.WriteLine("-------------------------\n");

            while (Continue)
            {
                try
                {
                    Console.WriteLine("\nType a string to encrypt:");
                    string UserString = Console.ReadLine();

                    Console.Write("\nShift: ");
                    int key = Convert.ToInt32(Console.ReadLine());

                    Console.WriteLine("\nEncrypted Data: ");

                    string cipherText = Encrypt(UserString, key);
                    Console.WriteLine(cipherText);
                    Console.Write("\n");

                    Console.WriteLine("Decrypted Data:");

                    string t = Decrypt(cipherText, key);
                    Console.WriteLine(t);

                    Console.WriteLine("\nDo you want to continue?");
                    Console.WriteLine("Type in Yes to continue or press any other key and then press enter to quit:");
                    string response = Console.ReadLine();
                    Continue = (response == "Yes");

                }
                catch (FormatException)
                {
                    Console.WriteLine("You entered a bad operation, try another one");
                }
            }

        }
    }
}

This is what I am getting and it is incorrect.

Ceasar Cipher

Type a string to encrypt:
Hello World

Shift: 1

Encrypted Data:
cfmmp rpsme

Decrypted Data:
bello qorld

Do you want to continue?
Type in Yes to continue or press any other key and then press enter to quit:

The difficuty is that when encrypting uppercase letter , say 'Z' we can get lowercase one, eg 'd' :

  'Z' + 10 == 'd'     

Let's extract upper and lower cases and use modulo arithmetics:

  for (int i = 0; i < alphabet.Length; i++) {
    char letter = alphabet[i];

    if (letter == ' ')
      continue;

    letter = (char)(char.IsLower(letter)
      ? (letter - 'a' + shift) % 26 + 26 + 'a'
      : (letter - 'A' + shift) % 26 + 26 + 'A');

    // Store.
    alphabet[i] = letter;
  }

Or extracting three cases:

  1. Lower case letters 'a'..'z'
  2. Upper case letters 'A'..'Z'
  3. Other characters (keep them as they are)

Code:

static string Encrypt(string value, int shift) {
  if (string.IsNullOrEmpty(value))
    return value; // Nothing to encrypt

  // ensure, that shift is in [0..25] range
  shift = ((shift % 26) + 26) % 26; 

  StringBuilder sb = new StringBuilder(value.Length);

  foreach(char letter in value)
    if (letter >= 'a' && letter <= 'z')
      sb.Append((char) ((letter - 'a' + shift) % 26 + 'a'));
    else if (letter >= 'A' && letter <= 'Z')
      sb.Append((char) ((letter - 'A' + shift) % 26 + 'A')); 
    else
      sb.Append(letter);

  return sb.ToString();
} 

// shift % 26 - in order to avoid integer overflow when shift == int.MinValue
static string Decrypt(string value, int shift) => 
  Encrypt(value, 26 - shift % 26);

Demo:

  string initial = "Hello World!";
  int shift = 10;

  string encrypted = Encrypt(initial, shift);
  string decrypted = Decrypt(encrypted, shift);

  Concole.Write($"{initial} -> {encrypted} -> {decrypted}");

Outcome:

  Hello World! -> Rovvy Gybvn! -> Hello World! 

Yeah your encyrption is broken. 'H' is not equal to 'h'. This line

else if (letter < 'a')
            {
                letter = (char)(letter + 26);
            }

Will always run for capital letters, since ALL capital letters are < 'a'. 'H' = 72, so the above code evaluates to letter = (char)(72 + 26) , which shifted one to the right is 99 or 'c'.

Use char.IsUpper to split the logic. If char.IsUpper == true , then you need to handle this differently. Something like

if(letter.IsUpper()){
    if (letter < 'A') DoStuff
} else {
    if (letter < 'a') DoStuff
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM