Decryption negating special character like " !@#$%^&*()"

I was wondering how am i able to negate away the special character. For example when i key aaa for my decrypted text and move 3 space behind, it shows it ^^^ instead of www. Is there anything wrong with my coding? This is all the code that i have inside my c#

static void Main(string[] args)
{
    string UserInput = "";
    int shift;
    Shift OBSHIFT = new Shift();
    Console.WriteLine("Welcome to Ceasar Shift Program:");
    Console.WriteLine("********************************");
    Console.WriteLine("type a string to encrypt:");
    UserInput = Console.ReadLine();
    Console.WriteLine("How many chars would you like to shift?: :");
    shift = int.Parse(Console.ReadLine());
    Console.Write("Your encrypted string is: ");
    Console.WriteLine(OBSHIFT.Decrypt(UserInput, -shift));
    Console.Read();
}
class Shift
{
    public string Decrypt(string cipherString, int shift)
    {
        string userOutput = "";
        char[] a = cipherString.ToCharArray();
        for (int i = 0; i < cipherString.Length; i++)
        {
            char c = a[i];
            int temp;
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
            {
                temp = (int)(a[i] + shift);
                if ((c >= 'A' && c <= 'Z' && temp > 'Z') || (c >= 'a' && c <= 'z' && temp > 'z'))
                    temp = temp + 26;
                else
                    temp = (int)(a[i] + (shift));
            }
            else
                temp = c;
            userOutput += (char)temp;
        }
        return userOutput;
    }
}
Jon Skeet
people
quotationmark

The problem is with this piece of code which does the actual shifting:

if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
{
    temp = (int)(a[i] + shift);
    if ((c >= 'A' && c <= 'Z' && temp > 'Z') || (c >= 'a' && c <= 'z' && temp > 'z'))
        temp = temp + 26;
    else
        temp = (int)(a[i] + (shift));
}

I would suggest restructuring in a few ways:

  • Make sure your shift is always positive to start with, so you only need to worry about going "past" the end of a particular set of characters
  • Use two separate branches, one for a-z and one for A-Z
  • Use a StringBuilder to build your string instead of repeated string concatenation

So for example:

public string ShiftText(string input, int shift)
{
    // This makes sure the shift is *always* in the range 0-25.
    shift = ((shift % 26) + 26) % 26;

    StringBuilder output = new StringBuilder();
    foreach (char c in input)
    {
        if (c >= 'a' && c <= 'z')
        {
            // We'll sort this later
        }
        else if (c >= 'A' && c <= 'Z')
        {
            // We'll sort this later
        }
        else
        {
            output.Append(c);
        }
    }
    return output.ToString();
}

Now the bits inside the "sort this later" are simpler to work with. For the a-z part, for example:

int shifted = c + shift;
if (shifted > 'z')
{
    shifted -= 26;
}
output.Append((char) shifted);

... and then the same for A-Z, but testing against 'Z' instead of 'z'. Yes, this is effectively duplicate code - but it's only there twice, and I think it's simpler to have that duplication than extract it out.

people

See more on this question at Stackoverflow