Stat Tracker

Wednesday, June 18, 2014

Converting Base 10 to Base 32 (Or Any Base) in Apex

Recently I had the need to convert a base 10 number into a base 32 number in Salesforce. For my project I had a need to integrate SFDC with a legacy AS400 database to store records (contract records).

The Contract Number Requirements

The legacy database had an existing field that had a length of 9 for the contract number, with the first 4 characters a standard prefix, and each number which had to be unique.

For example the contract number looked like "POLY48GH3" where POLY was the prefix, and 48GH3 was the number. If you've ever worked with legacy AS400 databases you know they love to limit the amount of characters in a field! Furthermore we couldn't use the characters W,X,Y, or Z in the field and could only use 0-1, and A-V as uppercase only.

Fun requirements right!

The Solution

We quickly identified that if we used base 32 numbers we could get the most unique numbers out of the 5 available characters per our requirements (32^5=33554432 available numbers).  In Java you can achieve easily this via the standard class/method Integer.toString(integerVal,radix) where you can specify your radix (base). There is no corresponding method in Apex!

You can use EncodingUtils in apex to do Base64 and even Base128, but if you need to tailor your base you are out of luck. To do custom base conversions you need to write your own method to accomplish this, which I have provided below. You can tweak this method to create different base conversions as necessary. Also you could probably write this in a Formula Field with some additional work if you didn't want to do it in Apex.

I hope this helps folks. A big shoutout to the computer science blog from Erik Oosteral which outlines this logic for those who are interested.

-------------------
public static String generateBase32ContractNumber(Decimal decimalValue, Integer contractNumberLength)
{
try
{
Integer inputBase = 10;
Integer outputBase = 32;
String outputValue = ''
String numericBaseData = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
Integer x;
Integer maxBase = NumericBaseData.length();
if(DecimalValue == 0)
{
return '0';
}
else
{
while(decimalValue > 0)
{
      X = (Integer)(((DecimalValue/outputBase) - (Integer)(DecimalValue/OutputBase))* OutputBase + 1.5);
      System.debug('x' + x);
      OutputValue = NumericBaseData.subString(X - 1,X)+OutputValue;
      DecimalValue = Integer.valueOf(DecimalValue/OutputBase);
}
}
//We want to ensure all characters have a value. So if the Base 32 number is 10, and our Contract Number lenght is 5, we want to make the output String "00010"
while(OutputValue.length() < contractNumberLength)
{
OutputValue = '0' + OutputValue;
}
return OutputValue;
}catch(Exception e)
{
throw new Custom_Exception('There was an error converting the base values:' + e.getMessage());
}

}