Reputation: 359
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
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
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
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
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
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
Reputation: 6260
What's happening is this:
input = "a"
input = input.Replace("a", "z");
executes and now input = "z"
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
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