schoko Bong
schoko Bong

Reputation: 103

Is there a better way to replace number to alphabet

I have made a code that works but Is there a way to make it better

byte[] r = Convert.FromBase64String("XFEWtnopccImhpHTzGeoeXBg4ws=");
string c = BitConverter.ToString(r).Replace("-", string.Empty);
string h = c.Replace("A", "K").Replace("B", "L").Replace("C", "M").Replace("D", "N").Replace("E", "O")
    .Replace("F", "P").Replace("0", "A").Replace("1","B").Replace("2", "C").Replace("3", "D").Replace("4", "E")
    .Replace("5", "F").Replace("6", "G").Replace("7", "H").Replace("8", "I")
    .Replace("9", "J");
Console.WriteLine(h.ToLower());

It replace 0-9 with A-J example 0-A | 1-B | 2-C and it replace
A-F with K-P example A-K | B-L | C-M

output must be:
fmfbbglghkcjhbmccgigjbndmmghkihjhagaodal

Note: that this works I only want to know If there is a easier way to do that.

EDIT: Thanxs for all the answers I really dont know which one is the best one but I think that one I marked as answered should be it!

Upvotes: 3

Views: 480

Answers (6)

Henk Holterman
Henk Holterman

Reputation: 273844

The BitConverter.ToString(r).Replace() stuff is an awful detour.

const string lookup = "abcdefghijklmnop";

byte[] r = Convert.FromBase64String("XFEWtnopccImhpHTzGeoeXBg4ws=");
string h = string.Concat(r.Select(b => "" +  lookup[b >> 4] + lookup[b & 0xf]));

System.Diagnostics.Debug.Assert(h == "fmfbbglghkcjhbmccgigjbndmmghkihjhagaodal");

Optimized code:

const string lookup = "abcdefghijklmnop";
public string Decode(string input)
{
    byte[] buf = Convert.FromBase64String(input);
    var result = new StringBuilder(buf.Length*2);
    foreach (byte b in buf)
    {
        result.Append(lookup[b >> 4]).Append(lookup[b & 0xf]);
    }
    return result.ToString();
}

string h = Decode("XFEWtnopccImhpHTzGeoeXBg4ws=");
System.Diagnostics.Debug.Assert(h == "fmfbbglghkcjhbmccgigjbndmmghkihjhagaodal");

Upvotes: 2

Joel Coehoorn
Joel Coehoorn

Reputation: 416149

If you know the length in advance (and you do in this situation), .Net Core has an even better option than StringBuilder now (at least in terms of performance):

private static Dictionary<char, char> map = new Dictionary<char, char> {
    {'A', 'k'}, {'B', 'l'}, {'C', 'm'}, {'D', 'n'}, {'E', 'o'}, {'F', 'p'},
    {'0', 'a'},{'1', 'b'}, {'2', 'c'}, {'3', 'd'},{'4', 'e'}, {'5', 'f'},
    {'6', 'g'},{'7', 'h'},{'8', 'i'}, {'9', 'j'}
};

public static string GetMyString(string input)
{
    byte[] b = Convert.FromBase64String(input);
    string source = BitConverter.ToString(b);

    return string.Create(2*(input.Length+1)/3 , input, (r, d) => {
        int j = 0;
        foreach(char c in d)
        {   
            if (c == '-') continue;
            r[j++] = map[c];
        }
    });
}

Console.WriteLine(GetMyString("XFEWtnopccImhpHTzGeoeXBg4ws="));

If I were to use StringBuilder, I know I could easily remove that last .Replace() call and the ToLower() call, both of which allocate and copy whole new strings:

public static string GetMyString(string input)
{
    byte[] b = Convert.FromBase64String(input);
    string source = BitConverter.ToString(b);

    var result = new StringBuilder(2*(input.Length+1)/3);
    foreach(char c in input)
    {
        if (c == '-') continue;
        result.Append(map[c]);
    }
    return result.ToString();
}

I haven't benchmarked, but I would expect this to significantly out-perform the other Dictionary/StringBuilder-based answer... but that's what I get for taking longer to answer and providing two solutions ;)

See them in action.

Upvotes: 0

spinalfrontier
spinalfrontier

Reputation: 849

How about a regex solution?

    Dictionary<string, string> map = new Dictionary<string, string>{{"A", "K"}, {"B", "L"}, {"C", "M"}, {"D", "N"}, {"E", "O"}, 
                                                                    {"F", "P"}, {"0", "A"}, {"1", "B"}, {"2", "C"}, {"3", "D"}, 
                                                                    {"4", "E"}, {"5", "F"}, {"6", "G"}, {"7", "H"}, {"8", "I"}, 
                                                                    {"9", "J"}};

    byte[] r = Convert.FromBase64String("XFEWtnopccImhpHTzGeoeXBg4ws=");
    string c = BitConverter.ToString(r).Replace("-", string.Empty);

    var regex = new Regex(String.Join("|",map.Keys));
    var newStr = regex.Replace(c, m => map[m.Value]);
    Console.WriteLine(newStr.ToLower());

run it on dotnetfiddle

Upvotes: 0

Lucca Ferri
Lucca Ferri

Reputation: 1347

You could also do the following:

static string DecodeWithoutLinq(string encoded)
{
    char[] s = new char[encoded.Length];

    for (int i = 0; i < encoded.Length; i++)
    {
        char currentChar = encoded[i];

        if (char.IsLetter(currentChar))
            s[i] = (char)(encoded[i] + 10);
        else if (char.IsNumber(currentChar))
            s[i] = (char)('A' + (currentChar - '0'));
    }
    return new string(s).ToLower();
}

static string DecodeWithLinq(string encoded)
{
    return string.Concat(encoded.ToCharArray()
        .Select(s => char.IsLetter(s) ? (char)(s + 10) : (char)('A' + (s - '0')))).ToLower();
}

static void Main(string[] args)
{
    byte[] r = Convert.FromBase64String("XFEWtnopccImhpHTzGeoeXBg4ws=");
    string c = BitConverter.ToString(r).Replace("-", string.Empty);

    string decodedString1 = DecodeWithoutLinq(c);
    string decodedString2 = DecodeWithLinq(c);
    Console.WriteLine(decodedString1);
    Console.WriteLine(decodedString2);

    Console.ReadKey();
}

Just one way that doesn't involve string manipulation.

DecodeWithLinq isn't verifying if it's a number though. Can be easily added if needed.

Upvotes: 1

Steve
Steve

Reputation: 216363

You could store all your char transforms in a dictionary and then use a simple loop to replace the chars. Using a StringBuilder.Replace (using the char as input parameters overload) should be better because it avoids the constant creation of new strings at each string.Replace call and there is no worry about string size changes.

Dictionary<char, char> replacements = new Dictionary<char, char>
{
    {'A', 'K'}, {'B', 'L'}, {'C', 'M'}, {'D', 'N'}, {'E', 'O'}, {'F', 'P'},
    {'0', 'A'}, {'1', 'B'}, {'2', 'C'}, {'3', 'D'}, {'4', 'E'}, {'5', 'F'},
    {'6', 'G'}, {'7', 'H'}, {'8', 'I'}, {'9', 'J'}
};

void Main()
{

    byte[] r = Convert.FromBase64String("XFEWtnopccImhpHTzGeoeXBg4ws=");
    string c = BitConverter.ToString(r).Replace("-", string.Empty);

    StringBuilder sb = new StringBuilder(c);
    foreach(char x in replacements.Keys)
        sb.Replace(x, replacements[x]);
    Console.WriteLine(sb.ToString().ToLower());
 }

Upvotes: 3

Chris Dunaway
Chris Dunaway

Reputation: 11216

This is my solution which uses a couple of arrays and a bit of Linq.

void Main()
{
    string inputChars = "0123456789ABCDEF";
    string replacementChars = "ABCDEFGHIJKLMNOP";

    byte[] r = Convert.FromBase64String("XFEWtnopccImhpHTzGeoeXBg4ws=");
    string c = BitConverter.ToString(r);

    string result = new String(c.Where(ch => inputChars.Contains(ch))
                                .Select(ch => replacementChars[inputChars.IndexOf(ch)])
                                .ToArray());

    Console.WriteLine(result.ToLower());
}

Upvotes: 0

Related Questions