【问题标题】:JS: How to count in lettersJS:如何计算字母
【发布时间】:2018-11-11 06:46:14
【问题描述】:

我希望能够以 26 为底数,但只能使用字母表中的字母。

我可以涵盖A + 1 = BZ + 1 = AA 等基础知识,但我希望它适用于很长的“数字”,例如AZZEBERBZZ

目前我在 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";
    }
}

但这里的问题是,当我在 AZ 时,它只会返回 AAA 而不是 BA

我该如何解决这个问题?

额外背景:

我需要函数 getNextColumn,因为我使用此函数循环从 Excel 工作表创建的对象,其中的列在 base26 中计算,但只有字母,没有数字

【问题讨论】:

  • 什么是列,getNextColumn 与以 26 为底的算术有何关系?
  • @CertainPerformance,我添加了一些额外的上下文
  • 我会看看 Number.prototype.toStringparseInt,因为它们几乎涵盖了您需要的所有内容。

标签: javascript counting letters


【解决方案1】:

基本上,您可以使用一个函数来获取数值,然后使用另一个函数将数值转换回所需的格式。这允许进行算术运算。

要获取一个数字,您可以使用 parseInt 以 36 为底并修正 9(这仅获取字母的值)作为值,使用 Array#reduce 获取整个字母数。

26 的因数是字母表的长度,更靠左的字母的位值是 26 的倍数。

要返回转换后的值,您可以使用 toString 和基本 36 来转换为想要的字母。

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

【讨论】:

  • 不错的答案!就像我的问题的 cmets 中提到的那样,总是首选使用一些高阶函数,因为它们是高度优化的! (阅读这个 SO 问题:stackoverflow.com/questions/2651112/…
【解决方案2】:

这是使用递归函数的完美候选。

使用递归函数,您需要定义基本情况和递归情况。

您已经介绍了基本情况,在这种情况下是两种情况:

  • 输入以“Z”以外的其他字母结尾
  • 输入是“Z”

在所有其他情况下,您的输入会出现“递归情况”:

  • 以“Z”结尾
  • 总共超过 1 个字母

对于这种“递归情况”,您可以修剪最后一个“Z”(因为无论如何您都需要将其替换为“A”),然后再次调用此函数,如下所示:

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

【讨论】:

  • 您是否回答了自己的问题?
  • @bugs 有趣的部分是问题和答案之间的时间差,这意味着在发布问题的那一刻答案已经完全输入。
  • 嗯,一般来说绝对没问题,希望如此! ;) stackoverflow.com/help/self-answer@bugs
  • @eisbehr 好吧,如果我发布一个问题,然后找到解决我自己问题的方法,那么将它作为答案发布绝对没问题。但是,对于 OP 来说似乎并非如此,它在打开问题 10 秒后发布了一个精心制作的答案,而没有提及他们本身就是 OP。我并不是在暗示任何不好的事情,只是……很奇怪。
  • 是的,我已经回答了我自己的问题,因为我想分享我目前的知识,也许我可以得到更多的改进。我认为这也是 SO 的目标 :) 看看我的答案中的 cmets,我发现我可以改进!是的!
猜你喜欢
  • 1970-01-01
  • 2019-07-09
  • 2020-12-11
  • 2019-12-28
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
相关资源
最近更新 更多