27

I'm creating some client side functions for a mappable spreadsheet export feature.

I'm using jQuery to manage the sort order of the columns, but each column is ordered like an Excel spreadsheet i.e. a b c d e......x y z aa ab ac ad etc etc

How can I generate a number as a letter? Should I define a fixed array of values? Or is there a dynamic way to generate this?

Chris Spittles
  • 14,471
  • 10
  • 63
  • 83

7 Answers7

66

I think you're looking for something like this

    function colName(n) {
        var ordA = 'a'.charCodeAt(0);
        var ordZ = 'z'.charCodeAt(0);
        var len = ordZ - ordA + 1;
      
        var s = "";
        while(n >= 0) {
            s = String.fromCharCode(n % len + ordA) + s;
            n = Math.floor(n / len) - 1;
        }
        return s;
    }

// Example:

    for(n = 0; n < 125; n++)
            document.write(n + ":" + colName(n) + "<br>");
georg
  • 204,715
  • 48
  • 286
  • 369
  • 4
    Good answer, but I would have liked to have seen an explanation behind it. Things like 97 represents small 'a' etc. – donnapep Apr 17 '14 at 13:52
  • @georg Would you please explain how the base conversion works? I mean why `n = Math.floor(n / len) - 1`? Why are you subtracting `1` here? I am having a hard time getting the idea behind it. I read several answers here and there but couldn't understand why it works. Please explain :) – Yeasin Mollik Jul 09 '20 at 04:23
  • @YaseenMollik: hi, see https://stackoverflow.com/a/8798330/989121 for a good explanation. – georg Jul 09 '20 at 12:37
  • 1
    `Math.floor()` is a floating point operation, also n%len was already calculated above, and that line is `n = (n - n%len) / len -1;`. In this use case it is not a performance problem, but from my point of view it is more easy to read, because no FPU op is used to get an int – Daniele Cruciani Nov 30 '20 at 09:42
20

This is a very easy way:

function numberToLetters(num) {
    let letters = ''
    while (num >= 0) {
        letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[num % 26] + letters
        num = Math.floor(num / 26) - 1
    }
    return letters
}
gooostaw
  • 389
  • 2
  • 8
  • This doesn't work above 701. But then again I don't even know if columns can get to AAA – Cooper Dec 07 '21 at 01:42
  • @Cooper It works. For 701 returns "ZZ" and for 702 it returns "AAA". Then successively: "AAB", "AAC". Same as in Excel. – gooostaw Dec 08 '21 at 14:38
4
function getColumnDescription(i) {
  const m = i % 26;
  const c = String.fromCharCode(65 + m);
  const r = i - m;
  return r > 0
    ? `${getColumnDescription((r - 1) / 26)}${c}`
    : `Column ${c}`
}

Usage:

getColumnDescription(15)
"Column P"

getColumnDescription(26)
"Column AA"

getColumnDescription(4460)
"Column FOO"

2

If you have your data in a two-dimensional array, e.g.

var data = [
  ['Day', 'score],
  ['Monday', 99],
];

you can map the rows/columns to spreadsheet cell numbers as follows (building on the code examples above):

function getSpreadSheetCellNumber(row, column) {
  let result = '';

  // Get spreadsheet column letter
  let n = column;
  while (n >= 0) {
    result = String.fromCharCode(n % 26 + 65) + result;
    n = Math.floor(n / 26) - 1;
  }

  // Get spreadsheet row number
  result += `${row + 1}`;

  return result;
};

E.g. the 'Day' value from data[0][0] would go in spreadsheet cell A1.

> getSpreadSheetCellNumber(0, 0)
> "A1"

This also works when you have 26+ columns:

> getSpreadSheetCellNumber(0, 26)
> "AA1"
publicapps
  • 131
  • 1
  • 3
1

You can use code like this, assuming that numbers contains the numbers of your columns. So after this code you'll get the string names for your columns:

var letters = ['a', 'b', 'c', ..., 'z'];
var numbers = [1, 2, 3, ...];
var columnNames = [];
for(var i=0;i<numbers.length;i++) {
    var firstLetter = parseInt(i/letters.length) == 0 ? '' : letters[parseInt(i/letters.length)];
    var secondLetter = letters[i%letters.length-1];
    columnNames.push(firstLetter + secondLetter);
}
haynar
  • 5,841
  • 7
  • 32
  • 53
  • Thanks for that. That works great but it doesn't start with just a single character i.e. a, b, c, d....x, y, z, aa, ab, ac? – Chris Spittles Nov 23 '11 at 11:01
0

This covers the range from 1 to 1000. Beyond that I haven't checked.

function colToletters(num) {
  let a = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  if (num < 27) return a[num % a.length];
  if (num > 26) {
    num--;
    let letters = ''
    while (num >= 0) {
      letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[num % 26] + letters
      num = Math.floor(num / 26) - 1
    }
    return letters;
  }
}

I could be wrong but I've checked the other functions in this answer and they seem to fail at 26 which should be Z. Remember there are 26 letters in the alphabet not 25.

Cooper
  • 48,630
  • 6
  • 20
  • 48
0

Simple recursive solution:

function numberToColumn(n) {
  const res = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[n % 26];
  return n >= 26 ? numberToColumn(Math.floor(n / 26) - 1) + res : res;
}