1

I have got a problem with decrypting a Caesar cipher in C#. We have to do it manually, encrypt and decrypt. I want it to write all possibilities shifting one by one (then it is easy to see the right decryption, because other 25 possibilities are nonsense). The problem is that it writes only one possibility, not 26. I tried everything. Do you have any idea where is the problem?

string text = "Z programovani{}{}{}";
text = text.ToUpper();
string output = "";
int shift = 3;

foreach (char a in text)
{
    int x = (int)a;
    if (x >= 65 && x <= 90)
    {
        x += shift;
    }
    if (x == 32)
    {
        x -= shift;
    }
    if (x >90)
    {
        x = x - 26;
    }

    output += (char)x;
}
Console.WriteLine(output);

int i = 0;
do
{
    string decoded = "";

    foreach (char a in output)
    {
        int x = (int)a;
        if (x >= 65 && x <= 90)
        {
            x += 1;
        }
        if (x > 90)
        {
            x = x + 26;
        }

        decoded += (char)x;
    }
    i++;
    Console.WriteLine(decoded);
} while (i < 27);

Console.ReadKey();
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Arya
  • 11
  • 2
  • I'm not sure I understand the description of the problem. What do you mean by "we have to do it manually"? –  Oct 25 '18 at 13:59
  • Just that we shift it manually, for example to 3 or -5 etc. – Arya Oct 25 '18 at 14:04

2 Answers2

2

Let's extract a method (do not cram everyting into single Main; decompose your solution, make it simpler, easier to read and maintain):

private static string Caesar(string value, int shift) {
  if (null == value)
    return null;

  // Normalization: if we have shift out of [0..25] range, e.g. -3 or 125
  shift = ((shift % 26) + 26) % 26;

  StringBuilder sb = new StringBuilder(value.Length);

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

  return sb.ToString();
}

Then you can easily use it:

using System.Linq;

...

string text = "Z programovani{}{}{}";

// Let's use Linq; loop 
// for(int i = 0; i < 26; ++i) Console.WriteLine($"{i,2}: {Caesar(text, i)}");  
// is an alternative
string result = string.Join(Environment.NewLine, Enumerable
  .Range(0, 26)
  .Select(i => $"{i,2}: {Caesar(text, i)}"));

Console.Write(result);

Outcome:

 0: Z programovani{}{}{}
 1: A qsphsbnpwboj{}{}{}
 2: B rtqitcoqxcpk{}{}{}
 3: C surjudprydql{}{}{}
 4: D tvskveqszerm{}{}{}
 5: E uwtlwfrtafsn{}{}{}
 6: F vxumxgsubgto{}{}{}
 7: G wyvnyhtvchup{}{}{}
 8: H xzwoziuwdivq{}{}{}
 9: I yaxpajvxejwr{}{}{}
10: J zbyqbkwyfkxs{}{}{}
11: K aczrclxzglyt{}{}{}
12: L bdasdmyahmzu{}{}{}
13: M cebtenzbinav{}{}{}
14: N dfcufoacjobw{}{}{}
15: O egdvgpbdkpcx{}{}{}
16: P fhewhqcelqdy{}{}{}
17: Q gifxirdfmrez{}{}{}
18: R hjgyjsegnsfa{}{}{}
19: S ikhzktfhotgb{}{}{}
20: T jlialugipuhc{}{}{}
21: U kmjbmvhjqvid{}{}{}
22: V lnkcnwikrwje{}{}{}
23: W moldoxjlsxkf{}{}{}
24: X npmepykmtylg{}{}{}
25: Y oqnfqzlnuzmh{}{}{}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
0

When playing with Cypher, a common question is "How to handle Letter that are not in our base Alphabet?".
The idea of an alphabet is one simple way to handle [az AZ 09] range and even add punctuation. Here the minial version.

static string alphabet = "abcdefghijklmnopqrstuvwxyz";

Then with simple function to divide into simple task:
- ShiftChar, Shit the char in our alphabet with the cypher key.
- Cypher, cypher a word.
- AllCypher, compute all cypher.

char ShiftChar(char letter, int key, StringComparison comparisonType = StringComparison.CurrentCulture)
    => alphabet[EuclydianModulo(AlphabetIndex(letter, comparisonType) + key, alphabet.Length)];

int EuclydianModulo(int dividend, int divisor) //As % computes the remainder, not the modulo
    => ((dividend % divisor) + divisor) % divisor;

string Cypher(string word, int key, StringComparison comparisonType = StringComparison.CurrentCulture)
    => new string(  // To Return a string from char Array
        word.Select(x => // If letter is not in the alphabet, Don't crypt that letter. 
             alphabet.IndexOf(word, comparisonType) >= 0 ? ShiftChar(x, key, comparisonType) : x
            ).ToArray()
       );

List<string> AllCypher(string word, StringComparison comparisonType = StringComparison.CurrentCulture)
    => Enumerable.Range(0, alphabet.Length)
                  // If word is null, string.Empty.
                 .Select(key => Cypher(word??string.Empty, key, comparisonType))
                 .ToList();

internal void TestCase_SO_52991034()
{
    var inputTest = new[] { "cake", "Ufhp rd gtc bnym knaj itejs qnvztw ozlx.", null };
    var result = inputTest.Select(x => new { word = x, cypher = AllCypher(x) });


    var ignoreCase = AllCypher("ABC", StringComparison.CurrentCultureIgnoreCase);
    var caseSentitiv =  AllCypher("ABC");

    var crypt = Cypher("FooBar Crypt me!", 42, StringComparison.CurrentCultureIgnoreCase);
    var decrypt = Cypher(crypt, alphabet.Length - 42);
}

In addition, Decrypt is simply a crypt where the key is alphabet.Length - key:

string Decypher(string word, int key, StringComparison comparisonType = StringComparison.CurrentCulture)
    => Cypher(word, alphabet.Length - key, comparisonType);
Drag and Drop
  • 2,672
  • 3
  • 25
  • 37