16進数は[a-f]までですが、36進数なら全てのアルファベットを使えます
英単語なら完全に数値として読めます
10進数との相互変換
Ruby
"apple".to_i(36) #=>17995730
17995730.to_s(36) #=>"apple"
JavaScript
parseInt("apple", 36) //=>17995730
(17995730).toString(36) //=>"apple"
「apple」という単語が書かれているのでは無い
「17995730」という10進数の36進表記なのだ...
JavaScriptの整数の計算誤差について
JavaScriptの場合、桁数が多いと誤差が出ます
自然数の場合は2^53 (9,007,199,254,740,992)までなら問題無いです
記号も使いたい
36進数の文字種は0-9の数値と、a-zのアルファベットのみです
記号を使いたい場合、記号リストを用意して、0-9に割り当てて置換します
これで簡単な英文なら表現できます
lm.rb
base10 = 121448246333169538562105956741709730840134098137499009964148600669661648586559384734426780238529123084195348
base36 = base10.to_s(36)
# => "i0thought0what0i1d0do0was20i1d0pretend0i0was0one0of0those0deaf3mutes4"
symbols = " ',-."
puts base36.gsub(/[0-9]/){|d|symbols[d.to_i]}
# => "i thought what i'd do was, i'd pretend i was one of those deaf-mutes."
最初はbase36.tr("0-9", symbols)
としてましたが「^-\」を含んでいた場合にうまく変換できない可能性があるのでgsubにしました
(エスケープするにしても結局gsubしなければならないと思うので)
記号含めて変換する
base36utils.rb
module Base36Utils
def get_symbols(str)
syms = str.scan(/[^a-zA-Z]/).uniq.sort.join
end
def to_base36(base10, symbols="")
base10.to_s(36).gsub(/[0-9]/){|d|symbols[d.to_i]}
end
def to_base10(base36, symbols="")
base36.gsub(/[^a-zA-Z]/){|c|symbols.index(c)}.to_i(36)
end
end
sample.rb
require_relative 'base36utils'
include Base36Utils
str = "You know what I'd like to be? I mean if I had my goddamn choice, I'd just be the catcher in the rye and all."
syms = get_symbols(str)
base10 = to_base10(str, syms)
base36 = to_base36(base10, syms)
print "original: "; p str
# => "You know what I'd like to be? I mean if I had my goddamn choice, I'd just be the catcher in the rye and all."
print "symbols: "; p syms
# => " ',.?"
puts
puts "encoded (base10): "; p base10
# => 1160298464533611188100561590112133834453448123656789220667590285674166764197329933937388578689862569716412816858127688041239872565463587711302882017935722749774989021127
puts "decoded (base36): "; p base36
# => "you know what i'd like to be? i mean if i had my goddamn choice, i'd just be the catcher in the rye and all."
アンダーバー
Rubyの場合、36進数の文字列にアンダーバーを入れても読んでくれます
(ただの目印なので10進数に変換したら元に戻す方法はありません)
double_compile.rb
num = "double_compile".to_i(36) #=>64868740571137744994
puts num.to_s(36) #=> "doublecompile"