How to encode and decode any string into Base‑36 in C#

1 Answer

0 votes
using System;
using System.Collections.Generic;
using System.Text;

/*
    Base‑36 encoding/decoding in Mono‑compatible C#
    ----------------------------------------------
    Base‑36 digits: 0–9, A–Z

    Encoding:
      - Convert string → bytes (UTF‑8)
      - Convert bytes → big integer (base‑256)
      - Convert big integer → Base‑36

    Decoding:
      - Convert Base‑36 → big integer
      - Convert big integer → bytes (base‑256)
      - Convert bytes → original UTF‑8 string

    We implement our own big‑integer using List<uint> chunks (32‑bit).
*/

class Base36Codec
{
    private const string Base36Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    // Convert Base‑36 character → numeric value
    private static int Base36Value(char c)
    {
        if (c >= '0' && c <= '9') return c - '0';
        return c - 'A' + 10;
    }

    // Encode any string into Base‑36
    public static string EncodeToBase36(string input)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(input);

        // Big integer stored as 32‑bit chunks (little‑endian)
        List<uint> number = new List<uint>();
        number.Add(0);

        // Convert bytes → big integer (base‑256)
        foreach (byte b in bytes) {
            uint carry = b;

            for (int i = 0; i < number.Count; i++) {
                ulong value = (ulong)number[i] * 256UL + carry;
                number[i] = (uint)(value & 0xFFFFFFFFUL);
                carry = (uint)(value >> 32);
            }

            if (carry > 0)
                number.Add(carry);
        }

        // Convert big integer → Base‑36
        StringBuilder encoded = new StringBuilder();

        while (!(number.Count == 1 && number[0] == 0)) {
            uint remainder = 0;

            for (int i = number.Count - 1; i >= 0; i--) {
                ulong value = ((ulong)remainder << 32) | number[i];
                number[i] = (uint)(value / 36UL);
                remainder = (uint)(value % 36UL);
            }

            while (number.Count > 1 && number[number.Count - 1] == 0)
                number.RemoveAt(number.Count - 1);

            encoded.Append(Base36Digits[(int)remainder]);
        }

        // Reverse Base‑36 output
        char[] arr = encoded.ToString().ToCharArray();
        Array.Reverse(arr);
        return new string(arr);
    }

    // Decode Base‑36 back into original string
    public static string DecodeFromBase36(string encoded)
    {
        encoded = encoded.ToUpper();

        // Big integer stored as 32‑bit chunks (little‑endian)
        List<uint> number = new List<uint>();
        number.Add(0);

        // Convert Base‑36 → big integer
        foreach (char c in encoded) {
            int digit = Base36Value(c);
            uint carry = (uint)digit;

            for (int i = 0; i < number.Count; i++) {
                ulong value = (ulong)number[i] * 36UL + carry;
                number[i] = (uint)(value & 0xFFFFFFFFUL);
                carry = (uint)(value >> 32);
            }

            if (carry > 0)
                number.Add(carry);
        }

        // Convert big integer → bytes (base‑256)
        List<byte> bytes = new List<byte>();

        while (!(number.Count == 1 && number[0] == 0))
        {
            uint remainder = 0;

            for (int i = number.Count - 1; i >= 0; i--) {
                ulong value = ((ulong)remainder << 32) | number[i];
                number[i] = (uint)(value / 256UL);
                remainder = (uint)(value % 256UL);
            }

            while (number.Count > 1 && number[number.Count - 1] == 0)
                number.RemoveAt(number.Count - 1);

            bytes.Add((byte)remainder);
        }

        bytes.Reverse();
        return Encoding.UTF8.GetString(bytes.ToArray());
    }

    static void Main()
    {
        string text = "Hello Universe!";
        string encoded = EncodeToBase36(text);
        string decoded = DecodeFromBase36(encoded);

        Console.WriteLine("Original: " + text);
        Console.WriteLine("Base-36 encoded: " + encoded);
        Console.WriteLine("Decoded: " + decoded);
    }
}



/*
run:

Original: Hello Universe!
Base-36 encoded: LP4N024HJ1YVBVD84Y8TYQP
Decoded: Hello Universe!

*/

 



answered Jul 7 by avibootz
...