Skip to content

Commit

Permalink
fix alphabet indexAt and stringAt
Browse files Browse the repository at this point in the history
  • Loading branch information
chieveit authored and jkirschner committed May 13, 2021
1 parent 549f5cf commit d1dcef1
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 46 deletions.
26 changes: 18 additions & 8 deletions src/core/alphabet.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ const alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', '
export function stringAt(index) {
let str = '';
let cindex = index;
while (cindex >= alphabets.length) {
// Each loop iteration converts a base-26 (alphabet length) digit to a
// character [A-Z]. Because it works from least to most significant digit,
// each new character must be added to the FRONT of the string being built.
do {
str = alphabets[parseInt(cindex, 10) % alphabets.length] + str;
cindex /= alphabets.length;
cindex -= 1;
str += alphabets[parseInt(cindex, 10) % alphabets.length];
}
const last = index % alphabets.length;
str += alphabets[last];
} while (cindex >= 0);
return str;
}

Expand All @@ -30,12 +31,21 @@ export function stringAt(index) {
*/
export function indexAt(str) {
let ret = 0;
for (let i = 0; i < str.length - 1; i += 1) {
// Each loop iteration converts a digit from a base-26 [A-Z] string to a
// base 10 integer, working from most to least significant base-26 digit.
for (let i = 0; i < str.length; i += 1) {
// Calculate offset from 'A', which has character code 65
const cindex = str.charCodeAt(i) - 65;
const exponet = str.length - 1 - i;
ret += (alphabets.length ** exponet) + (alphabets.length * cindex);
// 'A' is interpreted as 0 when in the 0th digit, but as 1 when in any
// other digit. Therefore, we will increment cindex so that [0-25] is
// remapped to [1-26] for all digits, then decrement the result after the
// loop completes by 1 to remap the 0th digit back to [0-25]. For example,
// 'AA' will be converted to 11 by the loop, then decremented to 10 before
// being returned.
ret += (cindex + 1) * (alphabets.length ** exponet);
}
ret += str.charCodeAt(str.length - 1) - 65;
ret -= 1;
return ret;
}

Expand Down
52 changes: 14 additions & 38 deletions test/core/alphabet_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,30 @@ import {
describe('alphabet', () => {
describe('.indexAt()', () => {
it('should return 0 when the value is A', () => {
assert.equal(indexAt('A'), 0);
assert.equal(indexAt('A'), 1 * 26 ** 0 - 1);
});
it('should return 25 when the value is Z', () => {
assert.equal(indexAt('Z'), 25);
it('should return 27 when the value is AB', () => {
assert.equal(indexAt('AB'), 1 * 26 ** 1 + 2 * 26 ** 0 - 1);
});
it('should return 26 when the value is AA', () => {
assert.equal(indexAt('AA'), 26);
it('should return 730 when the value is ABC', () => {
assert.equal(indexAt('ABC'), 1 * 26 ** 2 + 2 * 26 ** 1 + 3 * 26 ** 0 - 1);
});
it('should return 52 when the value is BA', () => {
assert.equal(indexAt('BA'), 52);
});
it('should return 54 when the value is BC', () => {
assert.equal(indexAt('BC'), 54);
});
it('should return 78 when the value is CA', () => {
assert.equal(indexAt('CA'), 78);
});
it('should return 26 * 26 when the value is ZA', () => {
assert.equal(indexAt('ZA'), 26 * 26);
});
it('should return 26 * 26 + 26 when the value is AAA', () => {
assert.equal(indexAt('AAA'), (26 * 26) + 26);
it('should return 19009 when the value is ABCD', () => {
assert.equal(indexAt('ABCD'), 1 * 26 ** 3 + 2 * 26 ** 2 + 3 * 26 ** 1 + 4 * 26 ** 0 - 1);
});
});
describe('.stringAt()', () => {
it('should return A when the value is 0', () => {
assert.equal(stringAt(0), 'A');
});
it('should return Z when the value is 25', () => {
assert.equal(stringAt(25), 'Z');
});
it('should return AA when the value is 26', () => {
assert.equal(stringAt(26), 'AA');
});
it('should return BC when the value is 54', () => {
assert.equal(stringAt(54), 'BC');
});
it('should return CB when the value is 78', () => {
assert.equal(stringAt(78), 'CA');
assert.equal(stringAt(1 * 26 ** 0 - 1), 'A');
});
it('should return ZA when the value is 26 * 26', () => {
assert.equal(stringAt(26 * 26), 'ZA');
it('should return AB when the value is 27', () => {
assert.equal(stringAt(1 * 26 ** 1 + 2 * 26 ** 0 - 1), 'AB');
});
it('should return Z when the value is 26 * 26 + 1', () => {
assert.equal(stringAt((26 * 26) + 1), 'ZB');
it('should return ABC when the value is 730', () => {
assert.equal(stringAt(1 * 26 ** 2 + 2 * 26 ** 1 + 3 * 26 ** 0 - 1), 'ABC');
});
it('should return AAA when the value is 26 * 26 + 26', () => {
assert.equal(stringAt((26 * 26) + 26), 'AAA');
it('should return ABCD when the value is 19009', () => {
assert.equal(stringAt(1 * 26 ** 3 + 2 * 26 ** 2 + 3 * 26 ** 1 + 4 * 26 ** 0 - 1), 'ABCD');
});
});
describe('.expr2xy()', () => {
Expand Down

0 comments on commit d1dcef1

Please sign in to comment.