matsuda
2/24/2010 - 1:27 PM

digit_convertor.rb

#!/usr/bin/env ruby

class DigitConvertor
  attr_reader :n
  def initialize(chars)
    @n = chars.size
    @chars = chars
    @chars_hash = Hash[*(@chars).zip((0..@n).to_a).flatten]
  end

  def to(i)
    digit = []
    begin
      i, c = i.divmod @n
      digit << @chars[c]
    end while i > 0

    return digit.reverse.join ''
  end

  def from(str)
    i = str.split('').size - 1
    r = 0
    str.split('').each_with_index do |c, n|
      r += @n ** (i-n) * @chars_hash[c]
    end
    r
  end
end

if $0 == __FILE__
  eval DATA.read
end

__END__

$KCODE = 'u';

require 'test/unit'
class DigitConvertorTest < Test::Unit::TestCase
  def test_62
    d62 = DigitConvertor.new [('0'..'9'), ('a'..'z'), ('A'..'Z')].map {|r| r.to_a }.flatten
    assert_equal d62.n, 62
    assert_equal d62.to(62), '10'
    assert_equal d62.from('10'), 62
    assert_equal d62.to(10000), '2Bi'
    assert_equal d62.from('2Bi'), 10000
    i = 98798798735665662
    assert_equal i, d62.from(d62.to(i))
  end

  def test_31
    d31 = DigitConvertor.new [('0'..'9'), ('a'..'u')].map {|r| r.to_a }.flatten
    assert_equal d31.n, 31
    assert_equal d31.to(32), 32.to_s(31)
  end

  def test_multibyte
    d8 = DigitConvertor.new %w{☆ ★ ♪ △ ▼ ○ ● ◎}
    d8.to(987987987)
    d8.from("◎♪◎☆◎☆☆☆♪△")
  end
end