英数小文字だけ(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%程度しか短くならないので、あまり活用されることはないかも…
コメント
@il9437
1
上記、計算に誤りがあるようです。
上記で確認したところ、以下のようになりました。
こんな感じで組んでみました。
文字種テーブルの
characters
はとりあえず62文字にしてありますが、重複さえしなければ何文字でも対応できると思います。文字列ではなく配列で持たせてもそのまま対応できるはず。