tags:

views:

59

answers:

3

I need to convert an integer into a base64-character representation. I'm using OxA3's answer on this thread: http://stackoverflow.com/questions/923771/quickest-way-to-convert-a-base-10-number-to-any-base-in-net

How do I inverse this to get my original integer back, given a string?

A: 

I have a first-pass of a working version here, albeit I'm not sure how efficient it is.

public static int StringToInt(string encodedString)
    {
        int result = 0;
        int sourceBase = baseChars.Length;
        int nextCharIndex = 0;

        for (int currentChar = encodedString.Length - 1; currentChar >= 0; currentChar--)
        {
            char next = encodedString[currentChar];

            // For loop gets us: baseChar.IndexOf(char) => int
            for (nextCharIndex = 0; nextCharIndex < baseChars.Length; nextCharIndex++)
            {
                if (baseChars[nextCharIndex] == next)
                {
                    break;
                }
            }

            // For character N (from the end of the string), we multiply our value
            // by 64^N. eg. if we have "CE" in hex, F = 16 * 13.
            result += (int)Math.Pow(baseChars.Length, encodedString.Length - 1 - currentChar) * nextCharIndex;
        }

        return result;
    }
ashes999
A: 

If base-64 is really what you need rather than "any base" then everything you need is already built in to the framework:

int orig = 1337;
byte[] origBytes = BitConverter.GetBytes(orig);
string encoded = Convert.ToBase64String(origBytes);
byte[] decoded = Convert.FromBase64String(encoded);
int converted = BitConverter.ToInt32(decoded, 0);
System.Diagnostics.Debug.Assert(orig == converted);
Joel Mueller
god thats ugly compared to C. Don't know why people rave so much about this C#.
ldog
@ldog: Haha, I can't imagine that anybody who's ever raved about C# has picked *converting strings to integers for arbitrary bases* as a scenario in which it really shines. Comparing C# to C in general seems rather pointless to me, in fact. Suppose I complained about how hard it is to rapidly develop a rich GUI application in C and asked why anybody likes it.
Dan Tao
It doesn't look like it's working. The original function maps (1, 2, 3, 4) to (b, c, d, e); this one maps them to (AqAAAA, AgAAAA, AwAAAA, BAAAAA). Not the original intention, which is to use less characters for numbers.
ashes999
You said you wanted base-64. That's standard base-64 encoding on the 4 bytes that make up an integer (that is, 1 = [0x1, 0x0, 0x0, 0x0]). Unfortunately, `Convert.ToBase64String` only accepts byte arrays.
Joel Mueller
The original Stack Overflow post lays it out as converting to "any base int." That's what I'm after. Cheers though.
ashes999
A: 

Joel Mueller's answer should guide you the base-64 case.

In response to the preliminary code you've provided in your own answer, you can definitely improve its efficiency by changing the code to accomplish what your for loop is doing (effectively an O(N) IndexOf) to use a hash lookup (which should make it O(1)).

I am basing this on the assumption that baseChars is a field that you initialize in your class's constructor. If this is correct, make the following adjustment:

private Dictionary<char, int> baseChars;

// I don't know what your class is called.
public MultipleBaseNumberFormatter(IEnumerable<char> baseCharacters)
{
    // check for baseCharacters != null and Count > 0

    baseChars = baseCharacters
        .Select((c, i) => new { Value = c, Index = i })
        .ToDictionary(x => x.Value, x => x.Index);
}

Then in your StringToInt method:

char next = encodedString[currentChar];

// No enumerating -- we've gone from O(N) to O(1)!
if (!characterIndices.TryGetValue(next, out nextCharIndex))
{
    throw new ArgumentException("Input includes illegal characters.");
}
Dan Tao
Using a dictionary is a great idea.
ashes999