-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathbase_convert.js
142 lines (121 loc) · 3.85 KB
/
base_convert.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"use strict";
// baseConvert converts a given string with a given encoding alphabet
//
//
// Base is assumed from alphabet sizes.
// LeftPadding is for preceding padding characters. By default padding should
// be ignored as it carries no meaning. For example, for the base 7 alphabet
// of "ABCDEFG", the padding character is "A". For the base 8 alphabet of
// "01234567", the padding character is "0". Padding characters are preserved
// on a 1:1 character basis.
let LeftPadding = false;
/**
* BaseConvert converts a given string with a given encoding alphabet into
* another base with another given encoding alphabet.
* Base is assumed from alphabet sizes.
*
* @param {string} input Input string.
* @param {string} inAlph Input alphabet (i.e. 0123456789ABCDEF)
* @param {string} outAlph Output alphabet (i.e. ABCDEFGHJKLMNPQRSTUVWXYZ234567)
* @returns {string} output number
*/
function BaseConvert(input, inAlph, outAlph) {
console.log("baseConvert: ", input, inAlph, outAlph);
if (input === null || input == "" || inAlph == "" || outAlph == "") {
return null;
}
const fromBase = inAlph.length;
const toBase = outAlph.length;
const inAlphChars = inAlph.split('');
// if(fromBase == 1){
// console.log("In Unary Case Hit");
// }
// // TODO support base 1/ unary encoding decoding.
// if (toBase == 1) {
// console.log("Out Unary Case Hit");
// //return "1".repeat(parseInt(decimal)); // TODO possibly add to BaseConvert
// }
const add = (x, y, base) => {
// For base-1, just concatenate the arrays since each digit can only be 1
if (base === 1) {
return [...x, ...y];
}
let z = [];
const n = Math.max(x.length, y.length);
let carry = 0;
let i = 0;
while (i < n || carry) {
const xi = i < x.length ? x[i] : 0;
const yi = i < y.length ? y[i] : 0;
const zi = carry + xi + yi;
z.push(zi % base);
carry = Math.floor(zi / base);
i++;
}
return z;
}
const multiplyByNumber = (num, power, base) => {
if (num < 0) return null;
if (num === 0) return [0]; // Zero is legit.
// For base-1, multiplication is just repetition
if (base === 1) {
let result = [];
for (let i = 0; i < num; i++) {
result.push(...power);
}
return result;
}
let result = [];
while (true) {
num & 1 && (result = add(result, power, base));
num = num >> 1;
if (num === 0) break;
power = add(power, power, base);
}
return result;
}
// decodeInput finds the position of each character in alphabet, thus decoding
// input into a useful array.
const decodeInput = (input) => {
const digits = input.split('');
let arr = [];
for (let i = digits.length - 1; i >= 0; i--) {
// Check for character in alphabet
if (!(inAlphChars.includes(digits[i]))) {
throw new Error('character not in alphabet: ' + digits[i]);
}
const n = inAlph.indexOf(digits[i])
// Continue even if character is not found (possibly padding character,
// see check above.)
if (n == -1) continue;
arr.push(n);
}
return arr;
}
const digits = decodeInput(input);
if (digits == []) return null; // zero case is legit.
let outArray = []; // Array of character position.
let power = [1];
for (let i = 0; i < digits.length; i++) {
outArray = add(outArray, multiplyByNumber(digits[i], power, toBase), toBase);
power = multiplyByNumber(fromBase, power, toBase);
}
// Finally, decode array into characters.
let out = '';
// Add back left (preceding) padding characters.
if (LeftPadding) {
let inPad = inAlph.charAt(0);
let outPad = outAlph.charAt(0);
let i = 0;
while (i < input.length) {
if (input.charAt(i) !== inPad) break;
out += outPad;
i++;
}
}
for (let i = outArray.length - 1; i >= 0; i--) {
out += outAlph[outArray[i]];
}
// console.log(out);
return out;
}