How can I convert a 15 char Id value into an 18 char Id value?
Explanation of the algorithm: This is based on the algorithm given here. The example below is using a made up salesforce 15 char Id 001A000010khO8J
- Separate the 15 char Id into 3 groups of 5 chars. You now have 3 strings (the
triplet
variable below):001A0
,00010
andkhO8J
- Reverse each string. The three strings are now
0A100
,01000
andJ8Ohk
- In each string, convert all Uppercase chars to 1, all other chars to 0. The three strings are now
01000
,00000
and10100
. - Look up the corresponding char in the
BinaryIdLookup
based. This gives us a suffix ofIAU
. - The 3 chars generated (in order) are appended to the 15 char Id value, giving you an 18 char Id value of
001A000010khO8JIAU
.
I have created an implementation of this in C# and have tested this on a number of real Salesforce Ids and it seems to do the job. Code is in this gist or below:
static string Convert15CharTo18CharId(string id)
{
if (string.IsNullOrEmpty(id)) throw new ArgumentNullException("id");
if (id.Length == 18) return id;
if (id.Length != 15) throw
new ArgumentException("Illegal argument length. 15 char string expected.", "id");
var triplet = new List<string> { id.Substring(0, 5),
id.Substring(5, 5),
id.Substring(10, 5) };
var str = new StringBuilder(5);
var suffix = string.Empty;
foreach (var value in triplet)
{
str.Clear();
var reverse = value.Reverse().ToList();
reverse.ForEach(c => str.Append(Char.IsUpper(c) ? "1" : "0"));
suffix += BinaryIdLookup[str.ToString()];
}
return id + suffix;
}
static readonly Dictionary<string, char> BinaryIdLookup = new Dictionary<string, char>
{
{"00000", 'A'}, {"00001", 'B'}, {"00010", 'C'}, {"00011", 'D'}, {"00100", 'E'},
{"00101", 'F'}, {"00110", 'G'}, {"00111", 'H'}, {"01000", 'I'}, {"01001", 'J'},
{"01010", 'K'}, {"01011", 'L'}, {"01100", 'M'}, {"01101", 'N'}, {"01110", 'O'},
{"01111", 'P'}, {"10000", 'Q'}, {"10001", 'R'}, {"10010", 'S'}, {"10011", 'T'},
{"10100", 'U'}, {"10101", 'V'}, {"10110", 'W'}, {"10111", 'X'}, {"11000", 'Y'},
{"11001", 'Z'}, {"11010", '0'}, {"11011", '1'}, {"11100", '2'}, {"11101", '3'},
{"11110", '4'}, {"11111", '5'}
};
Java version:
public class SalesforceIDConverter
{
public static String convertID(String id)
{
if(id.length() == 18) return id;
String suffix = "";
for(int i=0;i<3;i++){
Integer flags = 0;
for(int j=0;j<5;j++){
String c = id.substring(i*5+j,i*5+j+1);
if(c.compareTo("A") >= 0 && c.compareTo("Z") <= 0){
flags += 1 << j;
}
}
if (flags <= 25) {
suffix += "ABCDEFGHIJKLMNOPQRSTUVWXYZ".substring(flags,flags+1);
}else suffix += "012345".substring(flags-26,flags-26+1);
}
return id+suffix;
}
public static void main(String[] args)
{
String id = "001M0000009odAH";
String convertedID = convertID(id);
System.out.println("id: " + id + "; converts to: " + convertedID);
}
}
Python version
import string
import sys
bin_lookup = {
'00000':'A',
'00001':'B',
'00010':'C',
'00011':'D',
'00100':'E',
'00101':'F',
'00110':'G',
'00111':'H',
'01000':'I',
'01001':'J',
'01010':'K',
'01011':'L',
'01100':'M',
'01101':'N',
'01110':'O',
'01111':'P',
'10000':'Q',
'10001':'R',
'10010':'S',
'10011':'T',
'10100':'U',
'10101':'V',
'10110':'W',
'10111':'X',
'11000':'Y',
'11001':'Z',
'11010':'0',
'11011':'1',
'11100':'2',
'11101':'3',
'11110':'4',
'11111':'5'
}
def sf_replace(incoming_id_char):
if incoming_id_char in string.ascii_uppercase:
return '1'
else:
return '0'
def expand_sf_id(incoming_sf_id):
if len(incoming_sf_id) != 15:
raise ValueError('id string must be exactly 15 characters long')
# split into list of 3 5-character chunks
id_chunks = map("".join, zip(*[iter(incoming_sf_id)]*5))
suffix = ''
for id_chunk in id_chunks:
# replace all capital letters with 1, non cap letters with 0
lookup_components = [sf_replace(id_char) for id_char in id_chunk]
# make it string and reverse it
lookup_chunk = "".join(lookup_components)[::-1]
# get the letter from the lookup table based on the reversed string
bin_replacement = bin_lookup[lookup_chunk]
suffix += bin_replacement
#add the suffix to the origional id
expanded_sf_id = incoming_sf_id + suffix
return expanded_sf_id
if __name__ == '__main__':
print expand_sf_id(sys.argv[1])