Skip to content

Instantly share code, notes, and snippets.

@fphilipe
Created November 12, 2012 08:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fphilipe/4058176 to your computer and use it in GitHub Desktop.
Save fphilipe/4058176 to your computer and use it in GitHub Desktop.
Obfuscated ids
module Base62
BASE_CHARS = '0SKVnQFHhGs9qo7p8cRW54duMYNXTCErx2tDmwO3kabfUB1elLvjiIgyJAZ6Pz'.split('')
BASE = BASE_CHARS.length
BASE_ENCODED_MIN_LENGTH = 1
def self.decode(number)
# assure string
number = number.to_s.reverse.split('')
decoded = 0
digits = number.length
# decode
digits.times do |i|
decoded+= BASE_CHARS.index(number[i]) * BASE**i
end
decoded
end
def self.encode(number)
if number.nil?
return nil
end
# assure numerical
number = number.to_i(10) unless number.is_a? Integer
encoded = ''
digits = (number > 0) ? 1 + (Math.log(number)/Math.log(BASE)).to_i : 0
# fill with leading zeros
(BASE_ENCODED_MIN_LENGTH - digits).times do
encoded << BASE_CHARS[0]
end
# convert the number
digits.times do |i|
divider = BASE**(digits - 1 - i)
encoded << BASE_CHARS[(number / divider).to_i]
number = number % divider
end
encoded
end
end
# extend Integer and String
class Integer
def to_base62
Base62.encode self
end
def from_base62
Base62.decode self
end
end
class String
def to_base62
Base62.encode self
end
def from_base62
Base62.decode self
end
end
@airhorns
Copy link

airhorns commented Apr 4, 2018

If anyone's looking for a terser version without the typechecks you can try this sucker:

module HandleMapper
  BASE_CHARS = '0SKVnQFHhGs9qo7p8cWR54duMYNXTCErx2tDmwO3kabfUB1elLvjiIgyJAZ6Pz'.split('')
  BASE = BASE_CHARS.length

  def self.decode(string)
    chars = string.split('')

    chars.each_with_index.inject(0) do |sum, (char, index)|
      sum + (BASE_CHARS.index(char) * BASE**index)
    end
  end

  def self.encode(number)
    digits = 1 + (Math.log(number)/Math.log(BASE)).to_i # floor'd log in the base of the string to get the length

    # loop over each digit removing the divisor at that digit position, capturing the number of times the divisor went into the number
    (0...digits).to_a.reverse!.inject([]) do |encoded, digit|
      divisor = BASE ** (digit)
      encoded << BASE_CHARS[(number / divisor).to_i]
      number = number % divisor
      encoded
    end.reverse!.join('')
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment