Annoying Bot
Annoying Bot

Reputation: 359

Reverse alphabetical value of individual characters in string

I would like to know how to reverse the individual characters in a string, without reversing the whole string literally. I used the code that is showed below and got the following results. I will also show what the result should be.

As you can see, I'm not getting the result that I expected in the beginning. Every individual character should be reversed, but I'm curious how to do this. The result above is what I got with the following code:

static void Main()
    {
        string input = "a29z3";

        //Reverse Letters
        input = input.Replace("a", "z");
        input = input.Replace("b", "y");
        input = input.Replace("c", "x");
        input = input.Replace("d", "w");
        input = input.Replace("e", "v");
        input = input.Replace("f", "u");
        input = input.Replace("g", "t");
        input = input.Replace("h", "s");
        input = input.Replace("i", "r");
        input = input.Replace("j", "q");
        input = input.Replace("k", "p");
        input = input.Replace("l", "o");
        input = input.Replace("m", "n");
        input = input.Replace("n", "m");
        input = input.Replace("o", "l");
        input = input.Replace("p", "k");
        input = input.Replace("q", "j");
        input = input.Replace("r", "i");
        input = input.Replace("s", "h");
        input = input.Replace("t", "g");
        input = input.Replace("u", "f");
        input = input.Replace("v", "e");
        input = input.Replace("w", "d");
        input = input.Replace("x", "c");
        input = input.Replace("y", "b");
        input = input.Replace("z", "a");

        //Reverse numbers
        input = input.Replace("0", "9");
        input = input.Replace("1", "8");
        input = input.Replace("2", "7");
        input = input.Replace("3", "6");
        input = input.Replace("4", "5");
        input = input.Replace("5", "4");
        input = input.Replace("6", "3");
        input = input.Replace("7", "2");
        input = input.Replace("8", "1");
        input = input.Replace("9", "0");

        Console.WriteLine(input);
    }

Suggestions and/or examples would be more than welcome!

Upvotes: 3

Views: 1357

Answers (7)

svick
svick

Reputation: 244807

Others already identified the problem: you replace one character with another, but then again replace that character with it's original value in some cases.

To write the code better, let's restate the question: you have two ranges of consecutive characters (a-z and 0-9) and you want to reverse characters inside each range.

So, for a single character, we test if it's inside each range and if it is, we reverse it:

private static readonly Tuple<char, char>[] Ranges =
    new[] { Tuple.Create('a', 'z'), Tuple.Create('0', '9') };

static char Reverse(char c)
{
    foreach (var range in Ranges)
    {
        var first = range.Item1;
        var last = range.Item2;

        if (c >= first && c <= last)
        {
            int index = c - first;
            int reverseIndex = (last - first) - index;
            return (char)(first + reverseIndex);
        }
    }
    return c;
}

This way, adding for example the A-Z range would be a very simple code change.

(I used Tuple here, because it's simple. If you worked with ranges of characters more, it would make sense to create a custom type for it.)

Now, reversing a string means reversing each character, which is exactly what Select() is for. But the result is IEnumerable, so we need to turn that back into a string:

static string Reverse(string s)
{
    return string.Concat(s.Select(Reverse));
}

Upvotes: 0

Austin Salonen
Austin Salonen

Reputation: 50225

As your commenters have posted, you're changing characters that had already been changed.

In your given example, this would've been the flow with your code:

a29z3 
z29z3  -> a to z
a29a3  -> z to a
a79a3  -> 2 to 7
a79a6  -> 3 to 6
a79a3  -> 6 to 3
a29a3  -> 7 to 2
a20a3  -> 9 to 0

This method will iterate over the given string.

// build the map; there's most likely a better way
var alpha = "abcdefghijklmnopqrstuvwxyz";
var digits = "0123456789";

var alphaMap = alpha.Zip(alpha.Reverse(), (k, v) => new {Key = k, Value = v});
var digitMap = digits.Zip(digits.Reverse(), (k, v) => new { Key = k, Value = v });

var map = alphaMap.Concat(digitMap)
                  .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);


// execute
var given = "a29z3";
Debug.WriteLine(new string(given.Select(c => map[c]).ToArray()));
// yields:  z70a6

Upvotes: 3

Jesse C. Slicer
Jesse C. Slicer

Reputation: 20157

One-liner (code golfing):

input = input.Aggregate(string.Empty, (s, c) => s + ((c >= 'a') && (c <= 'z') ? (char)('z' - c + 'a') : (c >= '0') && (c <= '9') ? (char)('9' - c + '0') : c));

Upvotes: 0

Lee
Lee

Reputation: 144136

This assumes your characters are all in the expected range, but you can do:

public static char Reverse(char c)
{
    if (Char.IsDigit(c))
    {
        return (char)((int)'9' - (int)c + (int)'0');
    }
    else
    {
        return (char)((int)'z' - (int)c + (int)'a');
    }
}

and then use Select to do the mapping:

string output = new string(input.Select(Reverse).ToArray());

Upvotes: 1

JohnFx
JohnFx

Reputation: 34909

The problem is that you are replacing the same letters twice. You need to loop through the string one item at a time and replace each character instead of repeatedly running replace on the whole string.

For example, something like this:

    static void Main(string[] args) {

    string input = "a29z3";
    string output = string.Empty;

    foreach (char letter in input.ToCharArray()) {
        output += replacementChar(letter);
    }

    Console.WriteLine(output);

    }

    static char replacementChar(char c) {

        switch (c) {
            case 'a': return 'z'; 
            case 'b': return 'y'; 
            // and so on

            default: return c;
        }

    }

I'd also recommend using a calculation on ASCII values to do the swap rather than a long list of replacements individually. Will be cleaner.

Upvotes: 1

System Down
System Down

Reputation: 6260

What's happening is this:

  1. Let's say the input = "a"
  2. input = input.Replace("a", "z"); executes and now input = "z"
  3. A few lines later input = input.Replace("a", "z"); is executed and now input = "a"

What you need to do is instead of replacing you build a new string. So you iterate through the characters in the string, find the reverse, and append it to the new string.

Upvotes: 2

John Koerner
John Koerner

Reputation: 38077

The problem you are having is you are doing a replace on character that have already been replaced. You replace a with z and then you later replace z with a.

I would use a dictionary to lookup the values and loop over the characters, building a new string:

    Dictionary<string, string> ReplaceDict = new Dictionary<string, string>();
    private void Form1_Load(object sender, EventArgs e)
    {
        //Reverse Letters
        ReplaceDict.Add("a", "z");
        ReplaceDict.Add("b", "y");
        ReplaceDict.Add("c", "x");
        ReplaceDict.Add("d", "w");
        ReplaceDict.Add("e", "v");
        ReplaceDict.Add("f", "u");
        ReplaceDict.Add("g", "t");
        ReplaceDict.Add("h", "s");
        ReplaceDict.Add("i", "r");
        ReplaceDict.Add("j", "q");
        ReplaceDict.Add("k", "p");
        ReplaceDict.Add("l", "o");
        ReplaceDict.Add("m", "n");
        ReplaceDict.Add("n", "m");
        ReplaceDict.Add("o", "l");
        ReplaceDict.Add("p", "k");
        ReplaceDict.Add("q", "j");
        ReplaceDict.Add("r", "i");
        ReplaceDict.Add("s", "h");
        ReplaceDict.Add("t", "g");
        ReplaceDict.Add("u", "f");
        ReplaceDict.Add("v", "e");
        ReplaceDict.Add("w", "d");
        ReplaceDict.Add("x", "c");
        ReplaceDict.Add("y", "b");
        ReplaceDict.Add("z", "a");

        //Reverse numbers
        ReplaceDict.Add("0", "9");
        ReplaceDict.Add("1", "8");
        ReplaceDict.Add("2", "7");
        ReplaceDict.Add("3", "6");
        ReplaceDict.Add("4", "5");
        ReplaceDict.Add("5", "4");
        ReplaceDict.Add("6", "3");
        ReplaceDict.Add("7", "2");
        ReplaceDict.Add("8", "1");
        ReplaceDict.Add("9", "0");
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
        StringBuilder output = new StringBuilder();
        string input = "a29z3";

        foreach (var c in input.ToCharArray())
        {
            output.Append(ReplaceDict[c.ToString()]);
        }

        MessageBox.Show(output.ToString()); 
    }

Upvotes: 3

Related Questions