Caesar Cipher Shift (using alphabet array)

2020-02-14 08:22发布

I am currently writing a Caesar Cipher program in C# for my assignment and I am having a problem.

I am approaching this task using an array where I store the whole alphabet and I declare a shift variable which is defined by character index in the array - the iteration of a for loop. The shift calculation is done in a foreach loop, that fetches a character from a string that is read from a text file. Foreach loop is contained within a for loop that iterates to output every possible shift.

However, the problem is that when I try to access the character in an array by a value of my shift variable, the program doesn't seem to access the character I want, it just outputs the same character as in the original string.

This is the code for the program:

using System; 
using System.IO;

public class caesar_shift
{
    public static void Main()
    {
        string file = @"C:\Users\terasss2\Desktop\Programming and Data Structures\caesarShiftEncodedText.txt";      //String variable that stores a file location
        string encrypted_text = File.ReadAllText(file);     //String variable that contains the text from a file. To get the text, the method in a class SystemIO is ran to read the text. It expects a parameter, which is a file directory.
        string decoded_text = " ";
        int shift = 0;
        char character = '0';

        char[] alphabet = new char[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'};

        Console.WriteLine("The encrypted text is \n{0}", encrypted_text);       //Display the encrypted text

        for(int i = 0; i < alphabet.Length; i++)        //Start a loop which will display 25 different candidates of decipher
        {
            foreach(char c in encrypted_text)
            {
                character = c;

                if(character == '\'' || character == ' ')
                    continue;

                shift = Array.IndexOf(alphabet, character) - i;     //Define a shift which is the index of a character in an alphabet array, take away the itteration of this loop. Store the result in a variable

                if(shift <= 0)
                    shift = shift + 26;

                if(shift >= 26)
                    shift = shift - 26;

                character = alphabet[shift];    //Set the character to a shifted letter by accessing the array element of a value shift

                Console.WriteLine(character);

                decoded_text = decoded_text + character; 
             }  

            Console.WriteLine("\nShift {0} \n {1}",i + 1, decoded_text);

         }
       }
}

3条回答
你好瞎i
2楼-- · 2020-02-14 08:57

I took a look at your code and made a slight adjustment. First of all, I converted it to a method that lets you pass in the string and the amount you want to shift, so that you can either call it in a loop from 0 to 25 to see all the permutations, or you can just get a single value. I also check to see if each character is actually in the array, and if it isn't, then don't change it (in your code you were only checking for '\' and ' ' characters:

public static string ShiftText(string input, int shiftAmount)
{
    if (input == null) return null;

    char[] alphabet =
    {
        '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'
    };

    shiftAmount %= 26; // Ensure shift is between 0 and 25

    var shiftedText = string.Empty;

    foreach (var character in input)
    {
        var index = Array.IndexOf(alphabet, character);

        if (index < 0)
        {
            // This character isn't in the array, so don't change it
            shiftedText += character;
        }
        else
        {
            var newIndex = index - shiftAmount;

            // If it's negative, wrap around to end of array
            if (newIndex < 0) newIndex += 26;

            shiftedText += alphabet[newIndex];
        }
    }

    return shiftedText;
}

But another way to do this that works for upper AND lower case, and which is less code, is to simply test if char.IsLetter(character), and then shift the ASCII value of the character within the same 0-25 range.

For example, this does the same as the code above, only it works for lower case letters as well. The difference here is that before we compare the character to our lowest valued character ('a' or 'A'), we test if char.IsLower() first. This way we stay within the ASCII range for this character set:

/// <summary>
/// This method takes the input string and shifts all letter characters 
/// to the left (subtracts) by the amount specified in shiftAmount, so 
/// if shiftAmount = 1, then 'M' becomes 'L', and 'a' becomes 'z'.
/// </summary>
/// <param name="input">The input string to apply changes to</param>
/// <param name="shiftAmount">A value from 0 to 25, used to shift the characters</param>
/// <returns>The modified (shifted) string</returns>
public static string ShiftText(string input, int shiftAmount)
{
    if (input == null) return null;

    // Ensure shift is between 0 and 25
    shiftAmount %= 26; 

    var result = string.Empty;

    // Loop through input and update result with shifted letters
    foreach (var character in input)
    {
        if (!char.IsLetter(character))
        {
            // If the character isn't a letter, don't change it
            result += character;
        }
        else
        {
            var newChar = (char) (character - shiftAmount);
            // Adjust newChar to stay within this character range
            if (newChar < (char.IsLower(character) ? 'a' : 'A')) newChar += (char) 26;
            result += newChar;
        }
    }

    return result;
}
查看更多
看我几分像从前
3楼-- · 2020-02-14 09:12

I played a bit with your code. The following gives you the solution, but you have to take care: you couldonly use capital letters, because theres a difference in upper and lower charts. I used the ToUpper() method. Works fine for me. I think that's what your problem was.

public static void Main()
    {
        string encrypted_text = "BCD";     //String variable that contains the text from a file. To get the text, the method in a class SystemIO is ran to read the text. It expects a parameter, which is a file directory.
        string decoded_text = " ";
        int shift = 0;
        char character = '0';
        encrypted_text = encrypted_text.ToUpper();

        char[] alphabet = new char[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' };

        Console.WriteLine("The encrypted text is \n{0}", encrypted_text);       //Display the encrypted text

        for (int i = 0; i < alphabet.Length; i++)        //Start a loop which will display 25 different candidates of decipher
        {
            decoded_text = "";
            foreach (char c in encrypted_text)
            {
                character = c;

                if (character == '\'' || character == ' ')
                    continue;

                shift = Array.IndexOf(alphabet, character) - i;     //Define a shift which is the index of a character in an alphabet array, take away the itteration of this loop. Store the result in a variable
                if (shift <= 0)
                    shift = shift + 26;

                if (shift >= 26)
                    shift = shift - 26;


                decoded_text += alphabet[shift];
            }
            Console.WriteLine("\nShift {0} \n {1}", i + 1, decoded_text);
        }
    }
查看更多
Evening l夕情丶
4楼-- · 2020-02-14 09:13

Why don't you just use character's ASCII values. I would convert ciphertext to lower case first. For example a's asci value is 97. I would write a method to extract 97 every characters so a=0,b=1..... z=25. Then for every character in your ciphertext get -3 shifted value of that char.For example input char d should return value 0 which corresponds a.

查看更多
登录 后发表回答