JS: How to count in letters

807 Views Asked by At

I want to be able to count in base 26, but only with the letters of the alphabet.

I can cover the basics like A + 1 = B and Z + 1 = AA, but i want it to work for very long "numbers" like AZZEBERBZZ

Currently i have the following code in JavaScript

function getNextColumn(currentColumn) {
    currentColumn = currentColumn.toUpperCase();
    let lastLetterCode = currentColumn.charCodeAt(currentColumn.length - 1);

    if(lastLetterCode < 90) {
        return currentColumn.slice(0, -1) + String.fromCharCode(lastLetterCode + 1);
    } else {
        return currentColumn.slice(0, -1) + "A";
    }
}

But the issue here is that when i'm at AZ it just returns AAA instead of BA

How can i solve this?

EXTRA CONTEXT:

I need the function getNextColumn because I use this function to loop over an object created from an excel sheet, where to columns are counted in base26 but only with letters and no numbers

2

There are 2 best solutions below

6
JustAnotherDev On BEST ANSWER

This is a perfect candidate to use a recursive function.

With a recursive function you need to define a base situation and a recursive situation.

You already covered the base situations, which are 2 situations in this case:

  • The input ends with some other letter than "Z"
  • The input is "Z"

In all other cases you have the "recursive situation" where your input:

  • Ends with a "Z"
  • and it's longer than 1 letter in total

For this "recursive situation" you can trim the last "Z" (because you need to replace it with an "A" anyway) and then recall this function again, like so:

function getNextColumn(currentColumn) {
    currentColumn = currentColumn.toUpperCase();
    let lastLetterCode = currentColumn.charCodeAt(currentColumn.length - 1);

    if(currentColumn === "Z"){
        return "AA";
    }

    if(lastLetterCode < 90) {
        return currentColumn.slice(0, -1) + String.fromCharCode(lastLetterCode + 1);
    }

    return getNextColumn(currentColumn.slice(0, -1)) + "A";
}
1
Nina Scholz On

Basically you could use one function to get a numerical value and another to convert the numerical value back to the wanted format. This allows to make arithmetic operations.

For getting a number, you could use parseInt with base 36 and a correction of 9 (this gets only the value of letters) for the value and Array#reduce for getting the whole number of letters.

The factor of 26 is the length of the alphabet and a letter more left has a place value of times 26.

For geting a converted value back, you could use toString with base 36 for conversion to the wanted letters.

function getValue(s) {
    return s.split('').reduce((r, a) => r * 26 + parseInt(a, 36) - 9, 0) - 1;
}

function setValue(n) {
    var result = '';
    do {
        result = (n % 26 + 10).toString(36) + result;
        n = Math.floor(n / 26) - 1;
    } while (n >= 0)
    return result.toUpperCase();
}

console.log(getValue('A'));              //    0
console.log(setValue(getValue('A')));
console.log(getValue('B'));              //    1
console.log(setValue(getValue('B')));
console.log(getValue('Z'));              //   25
console.log(setValue(getValue('Z')));
console.log(getValue('AA'));             //   26
console.log(setValue(getValue('AA')));
console.log(getValue('AZ'));             //   51
console.log(setValue(getValue('AZ')));
console.log(getValue('CZ'));             //  103
console.log(setValue(getValue('CZ')));
console.log(getValue('ZZ'));             //  701
console.log(setValue(getValue('ZZ')));
console.log(getValue('DXH'));            // 3335
console.log(setValue(getValue('DXH')));
.as-console-wrapper { max-height: 100% !important; top: 0; }