One of the things that is great about integers and longs is that they are easy to remember. However, when using this as identifiers that a human should be able to type in, they leave a lot to be desired. A integer in the billion range requires a user to enter 10 digits correctly. That’s hard to read, hard to keep your place, etc. There is a solution to this issue: represent the data using a radix other than 10. For English speakers, a radix of 36 is easily readable and maximizes the density while allowing for case insensitivity (no one wants to remember if they should type z or Z!).
Consider this, the value for int.MaxValue is written out as:
2147483647
As base 36, it is
zik0zj
6 characters instead of 10. Nice!
To do this, I wrote a simple function that converts a long (64 bits!) to any radix between 2 and 36. This is a basic first or second semester CS problem, I know. Still, this code is handy to have when you need it for converting numbers into something a person can type in:
static string ConvertToString(long value, int toBase)
{
if (toBase < 2 || toBase > 36)
{
throw new ArgumentOutOfRangeException("toBase",
"Must be in the range of [2..36]");
}
var values = new List<char>();
for (var val = '0'; val <= '9'; ++val)
{
values.Add(val);
}
for (var val = 'a'; val <= 'z'; ++val)
{
values.Add(val);
}
var builder = new StringBuilder();
bool isNegative = false;
if (value < 0)
{
value = -value;
isNegative = true;
}
do
{
long index = value%toBase;
builder.Insert(0, values[(int)index]);
value = value/toBase;
} while (value != 0);
if (isNegative)
{
builder.Insert(0, '-');
}
return builder.Length == 0 ? "0" : builder.ToString();
}
And, to go the other way:
static long ConvertToLong(string input, int fromBase)
{
if (fromBase < 2 || fromBase > 36)
{
throw new ArgumentOutOfRangeException("fromBase",
"Must be in the range of [2..36]");
}
if (string.IsNullOrEmpty(input)) return 0;
input = input.Trim();
var values = new List<char>();
for (var val = '0'; val <= '9'; ++val)
{
values.Add(val);
}
for (var val = 'a'; val <= 'z'; ++val)
{
values.Add(val);
}
var builder = new StringBuilder();
bool isNegative = false;
int startIndex = 0;
if (input[0] == '-')
{
isNegative = true;
++startIndex;
}
long retval = 0;
for(int index = startIndex; index < input.Length; ++index)
{
retval *= fromBase;
bool found = false;
for (int number = 0; number < fromBase; ++number)
{
if (input[index] == values[number])
{
retval += number;
found = true;
}
}
if (!found) break;
}
if (isNegative)
{
retval = -retval;
}
return retval;
}