To iterate is human, to recurse divine. --L. Peter Deutsch

Cambia.BaseN Documentation and Code Samples

Copyright © 2016 - Steve Lautenschlager

This article provides documentation and code samples for the Cambia.BaseN Nuget package for converting and representing base-N numbers.

For more in-depth info, please see this post: Intro to Number Bases and the Cambia.BaseN Package.

Get the Cambia.BaseN Nuget Package

You can download the Cambia.BaseN Nuget Package from Nuget.org.

Create an Alphabet

An alphabet is the set of unique digits used to represent a number. The number of unique digits in your alphabet is the base, or radix.

For example, base-10 (decimal) uses an alphabet with ten digits 0123456789. Base-16 (hexadecimal) uses an alphabet with sixteen digits 0123456789ABCDEF.


Built-in:

Go here to learn more about the built-in alphabets. Up to base-62 they are exactly what you'd expect, after that things can get a touch wonky.

However, our Cambia95 standard alphabet reduces the wonk.


// You'll need the following using statement
using Cambia.BaseN;

// Use one of the static properties for special alphabets.
// This is likely all you'll every need.

BaseNAlphabet alpha = null;
alpha = BaseNAlphabet.Base2;
alpha = BaseNAlphabet.Base8;
alpha = BaseNAlphabet.Base10;
alpha = BaseNAlphabet.Base16;
alpha = BaseNAlphabet.Base36;
alpha = BaseNAlphabet.Base62;
alpha = BaseNAlphabet.Base64;
alpha = BaseNAlphabet.Base64_RFC4648;
alpha = BaseNAlphabet.Base64_RFC4648_Safe;
alpha = BaseNAlphabet.Base72;
alpha = BaseNAlphabet.Base72_Safe;
alpha = BaseNAlphabet.Base85;
alpha = BaseNAlphabet.Base85_Ascii85;
alpha = BaseNAlphabet.Base94;
alpha = BaseNAlphabet.Base95;

// Or get an alphabet of any length based on a built-in alphabet:

int radix = 53;
alpha = BaseNAlphabet.GetCambia95Alphabet(radix);
alpha = BaseNAlphabet.GetAscii85Alphabet(radix);
alpha = BaseNAlphabet.Get_Base64_Rfc4648_Alphabet(radix);
alpha = BaseNAlphabet.Get_Base64_Rfc4648_Safe_Alphabet(radix);



Custom:


// Create the standard base-10 alphabet
BaseNAlphabet a = new BaseNAlphabet("0123456789");

// Create a bizarre reverse base-10 alphabet
BaseNAlphabet a = new BaseNAlphabet("9876543210");

// Use the unique letters in your name to create a funky personalized alphabet
// In my case, it's a base-4 alphabet
BaseNAlphabet a = new BaseNAlphabet("STEV");

// Reset resets the class as if it were freshly instantiated
a.Reset("MARY");

// You can also instantiate with a character array
a = new BaseNAlphabet(new char[]{'M', 'i', 'c', 'h', 'a', 'e', 'l' });

// Or reset with one
a.Reset(new char[]{'s','a','b','i','n','e'});




Properties:

Alphabets are principally used as inputs to other operations, but they have a few readonly properties which are mainly used internally, but which might still be useful for you to know about.



// Radix -
int base = BaseNAlphabet.Base10.Radix; // base = 10

// SupportsNegative - 
bool canDoNeg = BaseNAlphabet.Base10.SupportsNegative; // canDoNeg=true

// If an alphabet contains the minus sign, then it does not support negative numbers.
canDoNeg = BaseNAlphabet.Base64_RFC4648_Safe.SupportsNegative; // canDoNeg=false
canDoNeg = BaseNAlphabet.Base95.SupportsNegative; // canDoNeg=false

// ContainsWhitespace -
bool ws = BaseNAlphabet.Base10.ContainsWhiteSpace; // ws=false

// Base95 includes the space character as a digit so it does have whitespace
ws = BaseNAlphabet.Base95.ContainsWhiteSpace; // ws=true



The BaseConverter Class - Parsing and Converting

The BaseConverter class is a static object with all static methods to Parse, output and convert numbers in different bases.


Parse:



// If you want to use the BigInteger struct 
// which allows integers of unlimited size you may 
// need to include this namespace
using System.Numerics; 


// Parse a binary number
// BaseConverter.Parse(string number, BaseNAlphabet sourceAlphabet);
// If a number can't fit in the specified output type, you'll get an OverflowException

BigInteger bi = BaseConverter.Parse("010100011010", BaseNAlphabet.Base2);
Int64 lg = BaseConverter.ParseToInt64("010100011010", BaseNAlphabet.Base2);
UInt64 ulg = BaseConverter.ParseToUInt64("010100011010", BaseNAlphabet.Base2);
Int32 i = BaseConverter.ParseToInt32("010100011010", BaseNAlphabet.Base2);
UInt32 ui = BaseConverter.ParseToUInt32("010100011010", BaseNAlphabet.Base2);
Guid g = BaseConverter.ParseToGuid("010100011010", BaseNAlphabet.Base2);

// Parse a hex number

bi = BaseConverter.Parse("A73FFB397", BaseNAlphabet.Base16);
lg = BaseConverter.ParseToInt64("A73FFB397", BaseNAlphabet.Base16);
ulg = BaseConverter.ParseToUInt64("A73FFB397", BaseNAlphabet.Base16);
i = BaseConverter.ParseToInt32("A73FFB397", BaseNAlphabet.Base16);
ui = BaseConverter.ParseToUInt32("A73FFB397", BaseNAlphabet.Base16);
g = BaseConverter.ParseToGuid("A73FFB397", BaseNAlphabet.Base16);





TryParse:


// TryParse a binary number
// bool result = BaseConverter.TryParse(string number, BaseNAlphabet sourceAlphabet, out T num);

bool result = false;

BigInteger bi = new BigInteger();
result = BaseConverter.TryParse("010100011010", BaseNAlphabet.Base2, out bi);

long lg = 0;
result = BaseConverter.TryParse("010100011010", BaseNAlphabet.Base2, out lg);

ulong ulg = 0;
result = BaseConverter.TryParse("010100011010", BaseNAlphabet.Base2, out ulg);

int i = 0;
result = BaseConverter.TryParse("010100011010", BaseNAlphabet.Base2, out i);

uint ui = 0;
result = BaseConverter.TryParse("010100011010", BaseNAlphabet.Base2, out ui);

Guid g = Guid.Empty;
result = BaseConverter.TryParse("010100011010", BaseNAlphabet.Base2, out g);




ToBaseN:


// Transform a number to base-n 
// string output = BaseConverter.ToBaseN(T sourceNumber, BaseNAlphabet outputAlphabet);
// T=BigInteger, Guid, Int64, UInt64, Int32, UInt32

BigInteger bi = new BigInteger(1000);
string output = BaseConverter.ToBaseN(bi, BaseNAlphabet.Base2); // output=1111101000
output = BaseConverter.ToBaseN(bi, BaseNAlphabet.Base16); // output=3E8
output = BaseConverter.ToBaseN(bi, BaseNAlphabet.Base62); // output=G8

long lg = 1000;
output = BaseConverter.ToBaseN(lg, BaseNAlphabet.Base2); // output=1111101000
output = BaseConverter.ToBaseN(lg, BaseNAlphabet.Base16); // output=3E8
output = BaseConverter.ToBaseN(lg, BaseNAlphabet.Base62); // output=G8

ulong ulg = 1000;
output = BaseConverter.ToBaseN(ulg, BaseNAlphabet.Base2); // output=1111101000
output = BaseConverter.ToBaseN(ulg, BaseNAlphabet.Base16); // output=3E8
output = BaseConverter.ToBaseN(ulg, BaseNAlphabet.Base62); // output=G8

int i = 1000;
output = BaseConverter.ToBaseN(i, BaseNAlphabet.Base2); // output=1111101000
output = BaseConverter.ToBaseN(i, BaseNAlphabet.Base16); // output=3E8
output = BaseConverter.ToBaseN(i, BaseNAlphabet.Base62); // output=G8

uint ui = 1000;
output = BaseConverter.ToBaseN(ui, BaseNAlphabet.Base2); // output=1111101000
output = BaseConverter.ToBaseN(ui, BaseNAlphabet.Base16); // output=3E8
output = BaseConverter.ToBaseN(ui, BaseNAlphabet.Base62); // output=G8

Guid g = new Guid("00000000-0000-0000-0000-0000000003E8");
output = BaseConverter.ToBaseN(g, BaseNAlphabet.Base2); // output=1111101000
output = BaseConverter.ToBaseN(g, BaseNAlphabet.Base16); // output=3E8
output = BaseConverter.ToBaseN(g, BaseNAlphabet.Base62); // output=G8




Convert:


// Convert a number directly from base-n to base-m 
// string output = BaseConverterConvert(string num, BaseNAlphabet sourceA, BaseNAlphabet, outputA);

string output = BaseConverter.Convert("1000", BaseNAlphabet.Base10, BaseNAlphabet.Base36); // output=RS

// Convert a Guid to Base72.
// This is obviously not the easy way to do this.  See the section on extension methods.
Guid g = new Guid("8C55203D-5DCF-4CC3-828C-A841F5EE5668");
string s = BaseConverter.Convert(g.ToString().ToUpper().Replace("-", ""), BaseNAlphabet.Base16, BaseNAlphabet.Base72);



Extension Methods

In order to make the use of extension methods you'll just need the using directive:


using Cambia.BaseN;


Then the following types:

  • BigInteger (may need a reference to System.Numerics for this type)
  • Int64
  • UInt64
  • Int32
  • UInt32
  • Guid

will all support the following methods:

  • Parse
  • TryParse
  • ToBaseN

Parse:


// Signature:
// num.Parse(string sourceNum, BaseNAlphabet sourceA);

// Parses "1111101000" as a base-2 number and returns the value.  
BigInteger bi = 0;
BigInteger bi2 = bi.Parse("1111101000", BaseNAlphabet.Base2); // bi=0, bi2=1000
bi = bi.Parse("1111101000", BaseNAlphabet.Base2); // bi=1000
 
// Behavior is similar for the other supported types: 
// Int64, UInt64, Int32, UInt32, Guid



TryParse:



// Signature:
// bool success = num.TryParse(string sourceNum, BaseNAlphabet sourceA, out T output);
// where T is one of the supported types.

// Attempts to parse "1111101000" as a base-2 number and returns that value in the out parameter.  
// If successful, return value is true.  NOTE:  Does not change the value of bi unless bi is 
// itself the out parameter passed into the method as follows
bool result = bi.TryParse("1111101000", BaseNAlphabet.Base2, out bi); // if success, bi=1000

// Parse the value into a different variable (bi2).
bi = 0;
result = bi.TryParse("1111101000", BaseNAlphabet.Base2, out bi2); // if success, bi=0, bi2=1000

// Behavior is similar for the other supported types: 
// Int64, UInt64, Int32, UInt32, Guid



ToBaseN:


// Signature:
// string output = num.ToBaseN(BaseNAlphabet targetAlphabet);

// Convert a type to a base-n representation
bi = 1000;
string num = bi.ToBaseN(BaseNAlphabet.Base2); // num=1111101000

// Behavior is similar for the other supported types: 
// Int64, UInt64, Int32, UInt32, Guid


Additional Examples


Quick Math:


// Add two binary numbers and represent them as a hex number
int b1 = 0;
int sum =   b1.Parse("1000101011001111", BaseNAlphabet.Base2) 
          + b1.Parse("111010100110000", BaseNAlphabet.Base2);
string hexNum = sum.ToBaseN(BaseNAlphabet.Base16); // hexNum = FFFF




Compress GUID for URL:

Even though GUIDs in URLs can be extremely useful, they're ugly. At 36 characters they take up a lot of real estate.

https://www.domain.com/8C55203D-5DCF-4CC3-828C-A841F5EE5668

This base-36 representation is less ugly (not much, but a little)

https://www.domain.com/8B377QEPEYB7BPRC75XTAE9NS

This base-62 representation is arguably not less ugly at all, but it's shorter

https://www.domain.com/4GnpMWOg6CP4Fg5Vfqu2Rs

Finally, this base-72 representation is pretty ugly, but it's safe for a URL and it's one character shorter.

https://www.domain.com/DMB!Ii;,n+Yb5l16c!uT!

It seems we have a sweet spot in the base-36 to base-62 range.


// Shortening your URL by converting your Guid to a different base
// and then back again is super easy

Guid g = new Guid("8C55203D-5DCF-4CC3-828C-A841F5EE5668");

// base-36
string shortGuid = g.ToBaseN(BaseNAlphabet.Base36);
g = g.Parse(shortGuid, BaseNAlphabet.Base36);

// base-62
shortGuid = g.ToBaseN(BaseNAlphabet.Base62);
g = g.Parse(shortGuid, BaseNAlphabet.Base62);

// base-72 safe
shortGuid = g.ToBaseN(BaseNAlphabet.Base72_Safe);
g = g.Parse(shortGuid, BaseNAlphabet.Base72_Safe);




 

Version: 6.0.20200920.1535