※本記事にはバグが含まれており、現在記事の修正中です。
詳細はコメント欄をご確認ください。
修正しました。
また、本記事より要領の良いコードをコメントにて投稿いただいています。ぜひそちらもご覧ください。
英数小文字だけ(36進数相当)
これがよくあるパターン。
console.log(106832262987743896n.toString(36));
// => "t7wvk33m1zs"
// パスワード向けに下8文字だけ採用する
console.log(106832262987743896n.toString(36).slice(-8));
// => "vk33m1zs"
英数大文字と小文字(62進数相当)
大文字を混ぜるので、ちょっと面倒なことをしています。
/**
* 10進数の文字列を62進数の文字列に符号化
* @param {string} id 10進数の文字列
* @returns {string}
*/
function encode(id) {
let n = BigInt(id);
let result = '';
let surplus = 0n;
while (n > 0) {
surplus = n % 62n;
result += surplus < 36n ? surplus.toString(36) : (surplus - 26n).toString(36).toUpperCase();
n /= 62n;
}
return result;
}
/**
* 62進数の文字列を10進数の文字列に復号
* @param {string} id 符号化した文字列
* @returns {string}
*/
function decode(id) {
let power = 0;
let char;
let result = 0n;
let num = 0;
// id 文字列が空になるまでループ
while (id) {
char = id.slice(0, 1); // 先頭から一文字取得
id = id.slice(1); // 先頭の一文字を削除
if (/[A-Z]/.test(char)) {
// 大文字の場合、parseInt()で計算できる様に数字を整形する
num = parseInt(char.toLowerCase(), 36) + 26;
} else {
// 小文字や数字の場合は普通に parseInt()
num = parseInt(char, 36);
}
result += BigInt(num * Math.pow(62, power));
power++; // 一つ上の桁を計算する
}
return result;
}
console.log(encode('106832262987743896'));
// => "axyFLT9iT7"
console.log(decode(encode('106832262987743896')));
// => 106832262987743896n
console.log(encode('106832262987743896').slice(-8));
// => "yFLT9iT7"
これだけ頑張っても上の簡単バージョンに比べて10%程度しか短くならないので、あまり活用されることはないかも…