Feel like sharing?

Converting GUID’s to Base36 and back again

GUID’s, or Globally Unique Identifiers, are a common sight in URLs, used for identification or referencing specific resources. However, their traditional 32-character hexadecimal format is not the most pleasing to the eye in a URL.

Optimally, a GUID should be converted to a Base-36 string that contains simple alphanumeric characters.

Many solutions opt to use base-64 for URL encoding, but this often results in producing characters (+, /, =) that are not URI-friendly. These characters cause problems as they are reserved characters in URLs and have a specific semantic meaning. This requires additional steps to replace and restore these characters during encoding and decoding, which in turn could present a potential for errors.

The beauty of the base-36 approach is that it only uses characters safe for use in URLs. It removes the need for extra decoding steps or error-prone replacements. Implementing methods in C# for this we get:

using System;
using System.Linq;
using System.Numerics;

					
public class Program
{
	public static void Main()
	{
		 Guid originalGuid = Guid.NewGuid();
        string base36String = originalGuid.ToBase36String();

        Console.WriteLine("Original GUID: "+originalGuid);
        Console.WriteLine("Base36 String: "+base36String);

        try
        {
            Guid convertedGuid = base36String.FromBase36String();
            Console.WriteLine("Converted GUID: "+convertedGuid);
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine("Error: "+ex.Message);
        }
	}
	
}

public static class GuidExtensions
{
    private static readonly string _chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public static string NewGuidToBase36String()
    {
        Guid newGuid = Guid.NewGuid();
        return newGuid.ToBase36String();
    }

    public static string ToBase36String(this Guid guid)
    {
        var bytes = guid.ToByteArray().Reverse().ToArray();
        var bigintBytes = new byte[bytes.Length + 1];
        bytes.CopyTo(bigintBytes, 0);
        BigInteger value = new BigInteger(bigintBytes);
        return ToBase36String(value);
    }

    private static string ToBase36String(BigInteger value)
    {
        if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), value, "value must be positive.");
        if (value == 0) return "0";

        string result = "";
        while (value > 0)
        {
            result = _chars[(int)BigInteger.Remainder(value, 36)] + result;
            value = BigInteger.Divide(value, 36);
        }

        return result;
    }

    public static Guid FromBase36String(this string base36)
    {
        if (base36 == null) throw new ArgumentNullException(nameof(base36));

        BigInteger value = FromBase36(base36);
        byte[] bytes = value.ToByteArray();

        // If the byte array is larger than 16 bytes due to the added 0 during conversion to BigInteger, trim it.
        if (bytes.Length > 16)
        {
            bytes = bytes.Take(16).ToArray();
        }

        return new Guid(bytes.Reverse().ToArray());
    }

    private static BigInteger FromBase36(string base36)
    {
        base36 = base36.ToUpper();
        BigInteger result = new BigInteger(0);
        BigInteger multiplier = new BigInteger(1);

        for (int i = base36.Length - 1; i >= 0; i--)
        {
            int value = _chars.IndexOf(base36[i]);
            if (value < 0) throw new ArgumentException("Invalid character in base36 string.", nameof(base36));
            result += value * multiplier;
            multiplier *= 36;
        }

        return result;
    }
}

In the encoding method, we’re converting the Guid to a string representation, parsing each hexadecimal character back to an integer, and then aggregating the result into a BigInteger with base-36.

While decoding, the base-36 string is segmented and parsed back to bytes, then to a Guid.

The base-36 encoded string gives you a shorter string than base-64, increasing the readability of your URLs, and avoiding the traps of reserved characters, enhancing the overall usability of your application.

Give it a try the next time you’re handling GUID’s in URLs and enhance not only their aesthetics but also their functionality!

Feel like sharing?

Last modified: October 23, 2023

Author