I have to make a URL shortener for query strings. Have spent few days trying to compress array data into base64 strings. Thinking that the best approach may be to interpret something like "[[1,2,9,3],[1,0,2],[39,4]]" as base13 with numbers 0-9 and [], symbols.
how the current algorithm works: convert the stringified arrays into an array of base13, where each element represents 1 unique character, convert this array to base10 number, convert this number to base 64 string.
but the problem is when converting the base13 array to base10 number, it makes large numbers like 5.304781188371057e+86 which cant be held in js.
I am open to alternative solutions of course, but please do not suggest something like creating a database of URLs as it won't work as I have up to 51!*51! unique URLs, better to just make a compact encodable and decodable query string and decode it as soon as the website is accessed.
//convert stringified array to array of base13(each element = each digit of base13 number)
function stringToArray(string)
{
let charSet = "[],1234567890";
let array = [];
for(let i = 0; i < string.length; i++)
{
array.push(charSet.indexOf(string[i]));
}
return array;
}
//convert base13 array to one large decimal number
function arrayToDecimal(array, base)
{
var decimal = 0;
for(let i = 0; i < array.length; i++)
{
decimal += array[i] * Math.pow(base, i)
}
return decimal;
}
//convert decimal number back to array
function decimalToArray(decimal, base)
{
var quotient = decimal;
var remainder = [];
while(quotient > base)
{
remainder.push(quotient % base)
quotient = Math.floor(quotient / base);
}
remainder.push(quotient % base)
return remainder;
}
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
// binary to string lookup table
const b2s = alphabet.split('');
// string to binary lookup table
// 123 == 'z'.charCodeAt(0) + 1
const s2b = new Array(123);
for(let i = 0; i < alphabet.length; i++)
{
s2b[alphabet.charCodeAt(i)] = i;
}
// number to base64
const ntob = (number) =>
{
if(number < 0) return `-${ntob(-number)}`;
let lo = number >>> 0;
let hi = (number / 4294967296) >>> 0;
let right = '';
while(hi > 0)
{
right = b2s[0x3f & lo] + right;
lo >>>= 6;
lo |= (0x3f & hi) << 26;
hi >>>= 6;
}
let left = '';
do {
left = b2s[0x3f & lo] + left;
lo >>>= 6;
} while(lo > 0);
return left + right;
};
// base64 to number
const bton = (base64) =>
{
let number = 0;
const sign = base64.charAt(0) === '-' ? 1 : 0;
for(let i = sign; i < base64.length; i++)
{
number = number * 64 + s2b[base64.charCodeAt(i)];
}
return sign ? -number : number;
};
console.log(decimalToArray(bton(ntob(arrayToDecimal([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 13))), 13))
//encoded and decoded, works output:[1,1,1,1,1,1,1,1,1,1,1,1,1]
console.log(arrayToDecimal([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 13))
//encoding doesnt work, array to decimal converts to 5.304781188371057e+86```