Skip to main content

Translates an existing number to a shorter alpha-numeric version.

// Translates a number to a short alhanumeric version
// C# Implementation
// http://kvz.io/blog/2009/06/10/create-short-ids-with-php-like-youtube-or-tinyurl/
//
// Translated any number up to 9007199254740992
// to a shorter version in letters e.g.:
// 9007199254740989 --> PpQXn7COf
//
// specifiying the second argument true, it will
// translate back e.g.:
// PpQXn7COf --> 9007199254740989
//
// Pro Tip
//
// You may want to remove vouwels (a, e, o, u, i) from $index as to avoid
// combinations that result in: 'penis' or other dirty words that could get your
// customers upset.
//
// You can also use the $pad_up argument to enforce a minimum length of 5
// characters as to avoid: 'nsfw' and 'wtf'.
//
// Thanks to William for pointing this out ; )
//

class ShortId
{
    public static readonly string Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static decimal BcPow(double a, double b)
    {
        return Math.Floor((decimal)Math.Pow(a, b));
    }

    public static ulong Decode(string value, int pad = 0)
    {
        value = ReverseString(value);
        var len = value.Length - 1;
        ulong result = 0;

        for (int t = len; t >= 0; t--)
        {
            var bcp = (ulong)BcPow(Alphabet.Length, len - t);
            result += (ulong)Alphabet.IndexOf(value[t]) * bcp;
        }

        if (pad > 0)
        {
            result -= (ulong)BcPow(Alphabet.Length, pad);
        }

        return result;
    }

    public static string Encode(byte[] value, int startIndex = 0, int pad = 0)
    {
        return Encode(BitConverter.ToUInt64(value, startIndex), pad);
    }

    public static string Encode(Guid guid, int pad = 0)
    {
        var bytes = guid.ToByteArray();

        var first = Encode(bytes, 0, pad);
        var second = Encode(bytes, 8, pad);

        return first + second;
    }

    public static string Encode(ulong value, int pad = 0)
    {
        var result = string.Empty;

        if (pad > 0)
        {
            value += (ulong)BcPow(Alphabet.Length, pad);
        }

        for (var t = (value != 0 ? Math.Floor(Math.Log(value, Alphabet.Length)) : 0); t >= 0; t--)
        {
            var bcp = (ulong)BcPow(Alphabet.Length, t);
            var a = ((ulong)Math.Floor((decimal)value / (decimal)bcp)) % (ulong)Alphabet.Length;
            result += Alphabet[(int)a];
            value  = value - (a * bcp);
        }

        return ReverseString(result);
    }

    private static string ReverseString(string value)
    {
        char[] arr = value.ToCharArray();
        Array.Reverse(arr);
        return new string(arr);
    }
}