短縮URLっぽい文字列の生成方法3つ

2012年04月05日

短縮URLっぽいURLの文字列。http://bit.ly/wEFnVF の場合「wEFnVF」の部分をどうやって生成するかちょっと考えてみたけど、大まかに三通りしかなさそうだというメモ。

1.一方向ハッシュ関数

MD5とか。この方法が一番手軽な場合けっこうあると思う。ただし、文字数がやたらと多くなってしまうため短縮URLとかでは使えない。


2.適当な文字列

ほとんどこれだと思う。ただし、重複チェックが必要になるので生成するたびにDBアクセスが発生するし、桁が上がる直前になると鬼のようにDBアクセスが発生するため工夫が必要。bitlyのように、あとからパスを変えられるタイプは大体これ形式なはず。


3.62進数

データベースの連番のidとかを62進数に変換すれば重複なしでスマートっぽくできる。元の10進数の数字を知られたくない場合、下のコードだと@n_mapの文字達を適当にすれば簡単には分からなくなる。

@n_map = { 1 => "0", 2 => "1", 3 => "2", 4 => "3", 5 => "4", 6 => "5",
           7 => "6", 8 => "7", 9 => "8", 10 => "9", 11 => "a", 12 => "b",
           13 => "c", 14 => "d", 15 => "e", 16 => "f", 17 => "g", 18 => "h",
    o">=> "h",
    o">=> "h",
    o">=> "h",
    o">=> "h",
    o">=> "h",
    o">=> "h",
    o">=> "h",=> "o", 26 => "p", 27 => "q", 28 => "r", 29 => "s", 30 => "t",
           31 => "u", 32 => "v", 33 => "w", 34 => "x", 35 => "y", 36 => "z",
           37 => "A", 38 => "B", 39 => "C", 40 => "D", 41 => "E", 42 => "F",
           43 => "G", 44 => "H", 45 => "I", 46 => "J", 47 => "K", 48 => "L",
           49 => "M", 50 => "N", 51 => "O", 52 => "P", 53 => "Q", 54 => "R",
           55 => "S", 56 => "T", 57 => "U", 58 => "V", 59 => "W", 60 => "X",
           61 => "Y", 62 => "Z" }

def convert62(i)
  digit = []
  begin
    i, c = i.divmod(62)
    digit << @n_map[c+1]
  end while i > 0

  return digit.reverse.join('')
end

puts convert62(123456) #=> "w7e"
      <div class="gist-meta"><a href="http://bit.ly/wEFnVF" target="_blank">
        </a><a href="https://gist.github.com/raw/2311121/ab93f352cb471707a7168fb48b32699b3f3841fe/convert62.rb" style="float:right;">view raw</a>
        <a href="https://gist.github.com/2311121#file_convert62.rb" style="float:right;margin-right:10px;color:#666">convert62.rb</a>
        <a href="https://gist.github.com/2311121">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
      </div>
    </div>


ちなみに  pic.kksg.net  では2の形式でやってます。

他に方法あるようでしたら@9mにリプライとかで教えてください〜


追記

@yamitzky さんに指摘してもらいましたがbase64url使えば64進数も可能ですね。パスに日本語使えば5万進数とかできるんじゃないかな…