I have a bunch of 10 digit integers that I\'m passing in a URL. Something like: \"4294965286\", \"2292964213\". They will always be positive and always be 10 digits.
I liked @user166390 answer but I preferred a most-to-least format and thought the code could be improved since the use of dictionary is unnecessary in encode and don't need to be generated on every decode. Also I added an exception and changed to ulong since negative values are not supported.
If somebody has further performance improvements feel free to write. Maybe if there is a better alternative to StringBuilder
Here is the code modified by me.
public static string EncodeNumber(ulong input)
{
return EncodeNumber(input, Mapping85Bit);
}
// This does not "pad" values
private static string EncodeNumber(ulong inp, char[] map)
{
// use ulong count instead of int since does not matter on x64 operating system.
ulong cnt = (ulong)map.Length;
// value -> character
if (inp == 0)
{
return map[0].ToString();
}
var sb = new StringBuilder();
while (inp > 0)
{
// encoded most-to-least significant
ulong val = inp % cnt;
inp = inp / cnt;
sb.Insert(0, map[(int)val]);
}
return sb.ToString();
}
public static ulong DecodeNumber(string encoded)
{
return DecodeNumber(encoded, Mapping85Bit, Mapping85BitDict);
}
private static ulong DecodeNumber(string encoded, char[] map, Dictionary charMapDict)
{
// use ulong count instead of int since does not matter on x64 operating system.
ulong b = (ulong)map.Length;
ulong res = 0;
for (var i = 0; i < encoded.Length; i++)
{
char ch = encoded[i];
if(!charMapDict.TryGetValue(ch, out ulong val))
{
throw new ArgumentException($"Invalid encoded number: '{encoded}'. '{ch}' is not a valid character for this encoding.");
}
res = (res * b) + val;
}
return res;
}
// Windows file system reserved characters: < > : " / \ | = *
///
/// Compatible with file system. Originates from ASCII table except starting like Base64Url and except windows path reserved chars. Skipped '/' and '\' to prevent path problems. Skipped ' for sql problems.
/// https://www.ascii-code.com/
/// Does not need to be encoded for json since it doesn't use \ and ". No encoding also needed for xml since < > are also not used. That is why it is also different to https://en.wikipedia.org/wiki/Ascii85
///
public static readonly char[] Mapping85Bit = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '-', '_', ' ', '!', '#', '$', '%', '&',
'(', ')', '+', ',', '.', ';', '?', '@', '[', ']',
'^', '`', '{', '}', '~'
};
private static readonly Dictionary Mapping85BitDict = Mapping85Bit.Select((v, i) => new { Value = v, Index = (ulong)i }).ToDictionary(i => i.Value, i => i.Index);
[Test]
public void EncodeTest()
{
// 85Bit Encoding:
Assert.AreEqual(EncodeNumber(85), "BA");
Assert.AreEqual(EncodeNumber(86), "BB");
Assert.AreEqual(EncodeNumber(3), "D");
Assert.AreEqual(EncodeNumber(84), "~");
Assert.AreEqual(EncodeNumber(0), "A");
Assert.AreEqual(DecodeNumber("BA"), 85);
Assert.AreEqual(DecodeNumber("BA"), 85);
Assert.AreEqual(DecodeNumber("`"), 81);
}