将数字转换为26个字符以外的字母

Convert numbers to letters beyond the 26 character alphabet

本文关键字:字符 数字 转换 26个      更新时间:2023-09-26

我正在为可映射的电子表格导出功能创建一些客户端函数。

我使用jQuery来管理列的排序顺序,但每个列都像Excel电子表格一样排序,即a b c de ......X y z aa ab ac AD等等等等

如何生成一个数字作为一个字母?我应该定义一个固定的值数组吗?或者是否有一种动态的方式来生成它?

我想你在找这样的东西

    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>");

这是一个非常简单的方法:

function numberToLetters(num) {
    let letters = ''
    while (num >= 0) {
        letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[num % 26] + letters
        num = Math.floor(num / 26) - 1
    }
    return letters
}
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}`
}

用法:

getColumnDescription(15)
"Column P"
getColumnDescription(26)
"Column AA"
getColumnDescription(4460)
"Column FOO"

简单递归解:

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

如果你的数据是一个二维数组,例如

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

您可以将行/列映射到电子表格单元格编号,如下所示(基于上面的代码示例构建):

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;
};

。数据[0][0]中的"日"值将放在电子表格单元格A1中。

> getSpreadSheetCellNumber(0, 0)
> "A1"

这也适用于当你有26+列:

> getSpreadSheetCellNumber(0, 26)
> "AA1"

您可以像这样使用代码,假设numbers包含您的列数。在这段代码之后,您将得到列的字符串名称:

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);
}

这里有一种依赖于.toString(26)的替代方法。它使用转换到26进制,然后将字符转换为a..z范围:

const conv = ((base, alpha) => { // Closure for preparing the function
    const map = Object.fromEntries(Array.from(alpha, (c, i) => [c, alpha[i + 10]]));
    return n => (n + base).toString(26).replace(/o*p/, "").replace(/./g, m => map[m]);
})(parseInt("ooooooooop0", 26), "0123456789abcdefghijklmnopqrstuvwxyz");
// Example:
for (let n = 0; n < 29; n++) console.log(n, conv(n));
console.log("...");
for (let n = 690; n < 705; n++) console.log(n, conv(n));

关于神奇数字

魔法值"ooooooooop0"导出如下:

  • 这是一个以基数26表示的数字,以标准的方式表示,即10位数字也起作用,然后是字母表的第一个字母。
  • 最伟大的"数字";在这个基数中,26是& & & &;(拉丁字母中的16个字母),以及"是第二大的。
  • 这个神奇的值是由一个足够长的序列组成的,这个序列由一个但最大的数字组成,后面跟着一个最大的数字,最后以0结尾。
  • 由于JavaScript的整数在Number.MAX_SAFE_INTEGER附近最大(更大的整数将遭受舍入错误),因此不需要有更长的一系列" 0 "他被选中了。我们可以看到Number.MAX_SAFE_INTEGER.toString(26)有12位数字,因此以26为基数确保精度高达11位,这意味着我们需要9 " 0 "。
  • 这个神奇的数字确保了如果我们给它加单位(以基数26为单位),我们将总是得到一个以一系列"0"开头的表示。然后是"& & & &"。这是因为在某一时刻,最后一位数字又会转到0,而"& & &;"也会绕到0,将前面的"o"p"帮助"。所以我们有了这个不变量数字总是以0或大于0开始;然后是& & &;

更通用的

上面的幻数可以通过代码得到,我们可以通过提供目标字母表来使它更通用。目标字母表的长度也直接决定了基数(即该字符串中的字符数)。

下面是与上面相同的输出,但使用了更通用的函数:

function createConverter(targetDigits) {
    const radix = targetDigits.length,
          alpha = "0123456789abcdefghijklmnopqrstuvwxyz",
          map = Object.fromEntries(Array.from(alpha, 
                (src, i) => [src, targetDigits[i]]
          )), 
          base = parseInt((alpha[radix-1]+'0').padStart(
               Number.MAX_SAFE_INTEGER.toString(radix).length - 1, alpha[radix-2]
          ), radix),
          trimmer = RegExp("^" + alpha[radix-2] + "*" + alpha[radix-1]);
    return n => (n + base).toString(radix)
                          .replace(trimmer, "")
                          .replace(/./g, m => map[m]);
}
// Example:
const conv = createConverter("abcdefghijklmnopqrstuvwxyz");
for (let n = 0; n < 29; n++) console.log(n, conv(n));
console.log("...");
for (let n = 690; n < 705; n++) console.log(n, conv(n));

现在可以很容易地调整为使用更精简的目标字母(例如不使用字母"l")和" 0 "),给出24的基数,而不是26:

function createConverter(targetDigits) {
    const radix = targetDigits.length,
          alpha = "0123456789abcdefghijklmnopqrstuvwxyz",
          map = Object.fromEntries(Array.from(alpha, 
                (src, i) => [src, targetDigits[i]]
          )), 
          base = parseInt((alpha[radix-1]+'0').padStart(
               Number.MAX_SAFE_INTEGER.toString(radix).length - 1, alpha[radix-2]
          ), radix),
          trimmer = RegExp("^" + alpha[radix-2] + "*" + alpha[radix-1]);
    return n => (n + base).toString(radix)
                          .replace(trimmer, "")
                          .replace(/./g, m => map[m]);
}
// Example without "l" and "o" in target alphabet:
const conv = createConverter("abcdefghijkmnpqrstuvwxyz");
for (let n = 0; n < 29; n++) console.log(n, conv(n));
console.log("...");
for (let n = 690; n < 705; n++) console.log(n, conv(n));

范围从1到1000。除此之外我没有检查过。

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;
  }
}

我可能错了,但我检查了这个答案中的其他函数,它们似乎在26处失败,应该是Z.记住字母表中有26个字母,而不是25个。

相关文章: