简体   繁体   中英

How to go out of bounds back to the start of an array?

I'm making a Caesar cipher, currently I have a shift of three that I want to encrypt the message with. If any letter has "x, y or z" it will give me an out of bounds array error (because the shift is 3).

How can I pass the error by going back to the start of the array, but ending with the remainder of the shift?

This is my code currently:

using System;
using System.Text;


//caesar cipher
namespace Easy47
{
    class Program
    {
        static void Main(string[] args)
        {
            const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            var input = Input(alphabet);
            Encrypt(3, input, alphabet);
            Console.WriteLine();
        }

        private static void Encrypt(int shift, string input, string alphabet)
        {
            var message = new StringBuilder();

            foreach (char letter in input)
            {
                for (int i = 0; i < alphabet.Length; i++)
                {
                    if (letter == alphabet[i])
                    {
                        message.Append(alphabet[i + shift]);
                    }
                }
            }

            Console.WriteLine("\n" + message);
        }

        private static string Input(string alphabet)
        {
            Console.Write("Input your string\n\n> ");

            string input = Console.ReadLine().ToUpper();

            return input;
        }
    }
}

You use the modulo operator:

var i = 255
var z = i % 200  // z == 55 

in your case here:

for (int i = 0; i < alphabet.Length; i++)
{
    if (letter == alphabet[i])
    {
        message.Append(alphabet[ (i + shift) % alphabet.Length]);
    }
}

If after your addition of shift the index is bigger then alphabet.Length it will start at 0 again.

See C# Ref Modulo Operator


Unrelated, but your loop is not very efficient. A message of "ZZZZZ" would go 5 times through your full alphabet to get translated. You should use a Dictionary as lookup. You can create it at the start before you translate the message and then your lookup is very fast - thats what dictionarys excel at. O(1) lookups :o)

If you know a little about linq, this should be understandable:

// needs:  using System.Linq;

private static void Encrypt(int shift, string input, string alphabet)
{
    var message = new StringBuilder();
    // create a string that is shifted by shift characters  
    // skip: skips n characters, take: takes n characters
    // string.Join reassables the string from the enumerable of chars
    var moved = string.Join("",alphabet.Skip(shift))+string.Join("",alphabet.Take(shift));

    // the select iterates through your alphabet, c is the character you currently handle,
    // i is the index it is at inside of alphabet
    // the rest is a fancy way of creating a dictionary for 
    // a->d
    // b->e
    // etc   using alphabet and the shifted lookup-string we created above.
    var lookup = alphabet
        .Select( (c,i)=> new {Orig=c,Chiff=moved[i]})
        .ToDictionary(k => k.Orig, v => v.Chiff);


    foreach (char letter in input)
    {
        // if the letter is not inside your alphabet, you might want to add
        // it "as-is" in a else-branch. (Numbers or dates or .-,?! f.e.)
        if (lookup.ContainsKey(letter)) 
        {
            message.Append(lookup[letter]);
        }
    }

    Console.WriteLine("\n" + message);
}

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