Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Convert Salesforce IDs from 15 character to 18 characters (and back)
# Salesforce originally used case-sensitive 15-character IDs.
# Later they added three error-correcting characters to make their 18-character ID.
# This class converts from one to the other and back
#
# Usage:
# SalesforceId.convert('a0D30000001n7Pi') => 'a0D30000001n7PiEAC'
# OR
# SalesforceId.convert('a0D30000001n7PiEAC') => 'a0D30000001n7Pi'
# SalesforceId.convert('A0d30000001N7pIeAc') => 'a0D30000001n7Pi'
#
class SalesforceId
class << self
def convert(str)
raise 'can only convert strings' unless str.is_a?(String)
return convert15to18(str) if str.length == 15
return convert18to15(str) if str.length == 18
raise 'must be either 15 or 18'
end
def base32todecimal(char)
base32[char]
end
def decimaltobase32(dec)
Array(base32.rassoc(dec)).first
end
private
def base32
@@b32 ||= begin
hash = {}
('A'..'Z').each_with_index {|letter, idx| hash[letter] = idx }
('0'..'5').each_with_index {|digit, idx| hash[digit] = idx + 26 }
hash
end
end
def convert15to18(str)
bits = str.split('').collect {|char| (char =~ /[A-Z]/) ? '1' : 0 }
checkdigits = [
bits[0..4].join.to_i(2),
bits[5..9].join.to_i(2),
bits[10..14].join.to_i(2),
]
checkdigits = checkdigits.collect {|d| decimaltobase32(d) }.join
str + checkdigits
end
def convert18to15(str)
base = str[0..14].downcase.split('')
dec = str[-3..-1].upcase.split('').collect {|char| base32todecimal(char) }
bits = dec.map {|d| ("%05b" % d.to_i).split('') }.flatten
base.zip(bits).map {|char,bit| bit == '1' ? char.upcase : char }.join
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment