◆ 0~9と記号6つの16種類の文字列を64種類の文字を使った文字列に変換します
◆ 少しサイズが減って 中身がわからなくなります 

0123456789 の数字と , . など一部の記号の 10 文字ちょっとの種類の文字列で作られた構造でデータをやりとりしていたのですが 10数文字しか種類ないのをそのまま送るのってなんかムダな気がします
簡単にでもいいので圧縮してサイズを減らしたいです
圧縮すると直接見てもデータがどんなのかわからないですし一石二鳥です

ですが テキスト形式でかけないと困るので 0~9 と a~z と A~Z と記号ちょっとくらいに変換することにしました
10数文字だったのを 60文字以上の文字種で表現するので多少のサイズが小さくなるはずです

最初は単純に
parseInt(str, 12).toString(65)
とかでいけないかなと思ってました

ですが toString の N進数って 36 までしかできません
それにいったん int にパースするには 「,」 などの記号を a から順のアルファベットに変換しないとできません
さらに 文字列がすごく長いと int にしたときに表現できる範囲を超えますしいろいろ制限があります

それなら地道に変換しようと考えてみると 2 の階乗値じゃないとビット処理するのがたいへんそうなので 変換元は 16 種類で変換先は 64 種類にしました

なんか base64 みたいなことしてる気がします
ですが あっちは バイナリなどの文字で表現できないのも文字で表現させる代わりに文字数増やしてますけど 今回作ってるのは 64 文字にすることで文字数を減らします

結果こんなのができました
function cmpr(str){
var frombase = 16,
tobase = 64,
frombasedigit = Math.log2(frombase)
tobasedigit = Math.log2(tobase)
var g = genfn(prepare(str)),
buff = "",
ret = "",
dgt,
t

while((t = g()) !== "NaN"){
buff += ("000" + t).substr(-4)
if(buff.length < tobasedigit){
continue
}
bits = buff.substr(0, tobasedigit)
buff = buff.substr(tobasedigit)
ret += destchars(bits)
}
ret += (buff && destchars(buff)) + buff.length
return ret


function prepare(str){
return str.replace(/[\,\.\;\:\-\|]/g, function(m){
return {
",": "a",
".": "b",
";": "c",
":": "d",
"-": "e",
"|": "f",
}[m]
})
}

function genfn(str){
var ptr = 0
return function (){
var char = str.charAt(ptr++)
return parseInt(char, frombase).toString(2)
}
}

function destchars(bits){
var deci = parseInt(bits, 2)
return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUCVWXYZ_$".charAt(deci)
}
}
変換元は 0~9 と記号「,」「.」「;」「:」「-」「|」の 16 種類です
変換先は 0~9 と a~z と A~Z と記号「_」「$」の 64 種類です
特に意味は無いですが 記号は JavaScript で変数名に使える 2 つにしてみました


復元用の関数です
function expd(str){
var from_charlist = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"
var to_charlist = "0123456789,.;:-|"
var from_bit_digit = Math.log2(from_charlist.length)

var special_chars = str.substr(-2)
var endbits = tobits(special_chars.charAt(0)).substr(-special_chars.charAt(1))

var bits = str.substr(0, str.length - 2).split("").map(tobits).reduce(function(a, b){
return a + b
}, "") + endbits

return bits.replace(/..../g, function(e){
return to_charlist.charAt(parseInt(e, 2))
})

function tobits(char){
var deci = from_charlist.indexOf(char)
return ("00000" + deci.toString(2)).substr(-from_bit_digit)
}

}

圧縮変換のときは ムダにメモリが取られないようにこまめにビット値に変換してますが さすがに全部メモリにのらないような大規模になることはないと思って解凍変換のほうでは先に全体をビット値にしてます

勢いで作ってみただけなのでアルゴリズムが良いとは言えないと思います



*追記*
バグあったので修正しました

ついでにコードをもっと短くした版を作りました
var barc = (function (){
var srcbase = 16,
dstbase = 64,
srcbase_bitlen = Math.log2(srcbase),
dstbase_bitlen = Math.log2(dstbase),
srcchars = "0123456789,.;:-|",
dstchars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUCVWXYZ_$"

function zeropad(str, digit){
return ("0".repeat(digit) + str).substr(-digit)
}

function compress(str){
return str.replace(/./g, function(e){
return zeropad(srcchars.indexOf(e).toString(2), srcbase_bitlen)
}).replace(new RegExp(`(.{1,${dstbase_bitlen}}$)|.{${dstbase_bitlen}}`, "g"), function(m, a){
if(a){
return dstchars.charAt(parseInt(m, 2)) + m.length
}else{
return dstchars.charAt(parseInt(m, 2))
}
})
}

function expand(str){
return str.replace(/(.)(.)$|./g, function(m, a, b){
if(a){
return zeropad(dstchars.indexOf(a).toString(2), dstbase_bitlen).substr(-b)
}else{
return zeropad(dstchars.indexOf(m).toString(2), dstbase_bitlen)
}
}).replace(new RegExp(`.{${srcbase_bitlen}}`, "g"), function(e){
return srcchars.charAt(parseInt(e, 2))
})
}

return {
compress,
expand
}
})()