【问题标题】:Increment a string with letters?用字母增加字符串?
【发布时间】:2015-08-21 13:09:39
【问题描述】:

我需要将一个字符串从.. 递增到 aaazzz 并在控制台中写入每个递增(递增甚至是一个词吗?)。它会是这样的:

aaa
aab
aac
...
aaz

aba
abb
abc
...
abz

aca
acb

等等。到目前为止,我已经通过这样做增加了一个字母:

String.prototype.replaceAt = function(index, character) {
    return this.substr(0, index) + character + this.substr(index+character.length);
}

string = "aaa";

string = string.replaceAt(2, String.fromCharCode(string.charCodeAt(2) + 1));

//string == "aab"

但是,当最后一个字母是 z 时,我迷失了方向,然后它应该增加字母 2(索引 1)并将最后一个字母重置为 a

有没有人有或知道一个聪明的解决方案?谢谢!

【问题讨论】:

  • 是否也需要区分大小写?
  • ('Ostackoverflow.com/a/30687539/1636522 :-)
  • Node js 模块:npmjs.com/package/incstr

标签: javascript jquery increment


【解决方案1】:

假设你总是有 3 个字母(或任何其他设定数量的字母),我会想到:

每个字母都有单独的变量,所以不是:

string = "aaa";

有:

string1 = "a";
string2 = "a";
string3 = "a";

然后在每次迭代中增加你需要的那个。这可能需要一些试验和错误,并且看起来你是从右到左,大致如下:

if(string3 != "z"){
    // Increment string 3 by a letter
}else if(string2 != "z"){
    // Increment string 2 by a letter
}else if (string1 != "z"){
    // Increment string 1 by a letter
}else{
    // What ever you want to do if "zzz"
}

我没有对此进行测试,但应该很接近。

然后

string = string1 + string2+ string3

现在你只剩下一个变量,就像之前一样,你可以做你想做的事情(即输出等)

您也可以使用字符串数组来执行此操作,这样可以更轻松地更改字母数量,并且需要更多代码来计算数组长度和内容,但我想让它工作至少像上面一样静态优先。

【讨论】:

  • 我明白你的意思,但这不是要走的路。当然可以,但我的 3 个字母示例只是一个示例。
【解决方案2】:

下面的例子可以从a...a 工作到z...z

String.prototype.replaceAt = function(index, character) {
  return this.substr(0, index) + character + this.substr(index + character.length);
}

String.prototype.inc = function() {
  var stop = 'z';
  var start = 'a';
  var currentIndex = this.length - 1;
  var string = this.replaceAt(currentIndex, String.fromCharCode(this.charCodeAt(currentIndex) + 1));

  for (var i = string.length - 1; i > 0; i--) {
    if (string[i] == String.fromCharCode(stop.charCodeAt(0) + 1)) {
      string = string.replaceAt(i - 1, String.fromCharCode(string.charCodeAt(i - 1) + 1));
      string = string.replaceAt(i, String.fromCharCode(start.charCodeAt(0)));
    }
  }
  return string;
}

var string = "aaa";
var allStrings = string;
while(string != "zzz") {
  string = string.inc();
  allStrings += " " + string;
}
document.getElementById("current").innerHTML = allStrings;
<div id="current"></div>

【讨论】:

  • 那我怎样才能得到所有字母的完整列表呢?
  • 我只需要在控制台中输出 aaa 到 zzz 的每个字母。没有间隔或类似的东西。只是 aaa 到 zzz。
【解决方案3】:

我使用了您的代码并添加了一些新功能。

String.prototype.replaceAt = function(index, character) {
    return this.substr(0, index) + character + this.substr(index+character.length);
}

String.prototype.incrementAt = function(index) {
    var newChar = String.fromCharCode(this.charCodeAt(index) + 1); // Get the next letter that this char will be
    if (newChar == "{") { // If it overflows
        return this.incrementAt(index - 1).replaceAt(index, "a"); // Then, increment the next character and replace current char with 'a'
    }
    return this.replaceAt(index, newChar); // Replace this char with next letter
}

String.prototype.increment = function() {
    return this.incrementAt(this.length - 1); // Starts the recursive function from the right
}

console.log("aaa".increment()); // Logs "aab"
console.log("aaz".increment()); // Logs "aba"
console.log("aba".increment()); // Logs "abb"
console.log("azz".increment()); // Logs "baa"

这个incrementAt 函数是递归的并且递增它当前所在的字符。如果在此过程中溢出(字符变为{,在z 之后),它会在其所在字母之前的字母上调用incrementAt

这段代码的一个问题是,如果你尝试增加zzz,你会得到aaaz。这是因为它试图增加最后一个字符的第 -1 个字符。如果我稍后有时间,我会通过修复更新我的答案。

请注意,如果您开始使用不同长度的字符串,此解决方案将有效。例如,“aaaa” 可以算到“zzzz”。

【讨论】:

  • 那么我将如何从 aaa 转到 zzz 并对每个字符串执行一些操作?就像我想以从 aaa 到 zzz(或 aa 到 zz 以保持更简单)的所有方式来 console.log 一样?
  • 所以,你只需说类似myStr = "aa"; while (myStr!= "zz") { myStr = myStr.increment(); console.log(myStr); } 这样的话就可以让你通过 zz
【解决方案4】:

采用了一些算法方法。该函数将初始字符串作为参数,递增字母表中下一个可能的字符,最后返回结果。

function generate(str)
{
  var alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
  var chars = [];
  for(var i = 0; i < str.length; i++)
  {
    chars.push(alphabet.indexOf(str[i]));
  }
  for(var i = chars.length - 1; i >= 0 ; i--)
  {
    var tmp = chars[i];
    if(tmp >= 0 && tmp < 25) {
      chars[i]++;
      break;
    }
    else{chars[i] = 0;}
  }
  var newstr = '';
  for(var i = 0; i < chars.length; i++)
  {
    newstr += alphabet[chars[i]];
  }
  return newstr;
} 

这是循环辅助函数,它接受初始字符串循环并生成所有组合。

function loop(init){
  var temp = init;
  document.write(init + "<br>");
  while(true)
  {
    temp = generate(temp);
    if(temp == init) break;
    document.write(temp + "<br>");
  }
}

用法:loop("aaa");

CODEPEN

【讨论】:

  • 那么我如何从 aaa 转到 zzz 并在控制台中输出每个结果?
  • 我想我不明白。请更新您的答案。
  • 也可以,但我选择了另一个答案:)
  • 是的,那个人可能更有效率和天才。唯一缺少的是生成等长的 z 字符串。
【解决方案5】:

让我们试试这个方法。这是一个直接循环,从 aaa,aab,aac,.....,xzz,​​yzz,zzz

产生完整的序列

function printSeq(seq){
    console.log(seq.map(String.fromCharCode).join(''));
}


var sequences = [];

(function runSequence(){
    var seq = 'aaa'.split('').map(function(s){return s.charCodeAt(0)});
    var stopCode = 'z'.charCodeAt(0);
    do{
        printSeq(seq);
        sequences.push(seq.map(String.fromCharCode).join(''));
        if (seq[2]!=stopCode) seq[2]++;
        else if (seq[1]!=stopCode) seq[1]++;
        else if (seq[0]!=stopCode) seq[0]++;
    }while (seq[0]<stopCode);
    printSeq(seq);
    sequences.push(seq.map(String.fromCharCode).join(''));
})();

结果显示在控制台中,您还将获得存储在sequence 数组中的完整序列。希望这是可读和有用的。

【讨论】:

  • 你测试过代码吗?我从 aaa 转到 aaz,然后地狱就崩溃了。
  • 当然,我在回复之前重新运行了 sn-p,我得到了正确的结果。输出从 aaa、aab、... zzz 运行。您是从 StackOverflow sn-p 运行它还是将其复制到其他地方运行?
  • 我在 JSFiddle 中试过。感谢您的贡献,但我将其中一个标记为答案。
  • @Snorlax 不用担心。我也喜欢你选择的答案。我只是想提供一种不同的方法:)
【解决方案6】:

将字符串视为基数为 36 的数字。

将其转换为十进制,加 1,转换回基数 36,并将任何零替换为字母“a”:

var str= 'aaa',
    s= str;

while(str!=='zzz') {
  str= ((parseInt(str, 36)+1).toString(36)).replace(/0/g,'a');
  s+= ' '+str;
}

document.body.innerHTML= s;

【讨论】:

  • 迄今为止的最佳答案。谢谢。
  • 以 36 为基数的很好的捕获 :)
  • 谢谢。真正的诀窍是处理数字 0-9,直到我意识到只有数字 0 会出现,因为我们递增 1。用字母 'a' 替换可以处理。
  • 为了更通用,您可以使用此方法生成 z 字符串:stackoverflow.com/questions/14343844/…
  • 对于动态长度添加:str = str.replace(/1/g,'a');s+= ' '+str;之前
【解决方案7】:

Number#toString 的有趣方法:

var n = 13330
var ns = []

for(var i = 0; i < 26; i++) {
  for(var j = 0; j < 26; j++) {
    for(var k = 0; k < 26; k++) {
      ns.push(n.toString(36))
      n++
    }
    n += 10 // jump from '(x)0' to '(x+1)a', etc.
  }
  n += 360 // jump from '(x)0a' to '(x)aa', etc.
}

console.log(ns) // the strings you wanted

【讨论】:

    【解决方案8】:

    此函数根据数字给出 3 个字符:

    function n2s (n) {
        var s = '';
        while (s.length < 3) {
            s = String.fromCharCode(97 + n % 26) + s;
            n = Math.floor(n / 26);
        }
        return s;
    }
    

    打印从“aaa”到“zzz”的字符串:

    var zzz = Math.pow(26, 3) - 1;
    for (var n = 0; n <= zzz; n++) {
        console.log(n2s(n));
    }
    

    function n2s (n) {
        var s = '';
        while (s.length < 3) {
            s = String.fromCharCode(97 + n % 26) + s;
            n = Math.floor(n / 26);
        }
        return s;
    }
    
    var result = [];
    var zzz = Math.pow(26, 3) - 1;
    for (var n = 0; n <= zzz; n++) {
        result.push(n2s(n));
    }
    document.body.innerHTML = result.join(' ');

    询问详情:-)


    改进

    accepted answerhttp://jsperf.com/10-to-26 相比的性能。

    // string to number: s2n("ba") -> 26
    function s2n(s) {
        var pow, n = 0, i = 0;
        while (i++ < s.length) {
            pow = Math.pow(26, s.length - i);
            n += (s.charCodeAt(i - 1) - 97) * pow;
        }
        return n;
    }
    
    // number to string: n2s(26) -> "ba"
    function n2s(n) {
        var s = '';
        if (!n) s = 'a'; 
        else while (n) {
            s = String.fromCharCode(97 + n % 26) + s;
            n = Math.floor(n / 26);
        }
        return s;
    }
    
    // pad("ba", 4) -> "aaba"
    function pad (s, n) {
        while (s.length < n) s = 'a' + s;
        return s;
    }
    

    用法:

    var from = s2n('azx');
    var to = s2n('baa');
    for (var n = from; n <= to; n++) {
        console.log(pad(n2s(n), 3));
    }
    

    输出:

    azx
    azy
    azz
    baa
    

    递归性

    在内存使用或计算时间方面可能效率较低:https://jsperf.com/10-to-26/4

    function n2s(n) {
        var next = Math.floor(n / 26);
        return (
            next ? n2s(next) : ''
        ) + (
            String.fromCharCode(97 + n % 26)
        );
    }
    
    function s2n(s) {
        return s.length && (
            (s.charCodeAt(0) - 97)
        ) * (
            Math.pow(26, s.length - 1)
        ) + (
            s2n(s.slice(1))
        );
    }
    

    【讨论】:

    • 这个答案值得更多的支持。它比公认的答案更通用。更改一些硬编码数字后适用于任何字母表。
    • 是否可以在n2s(n)中得到aaa
    • @bouh 我不这么认为,因为a 代表0,但你可以使用pad 函数来做到这一点:pad("", 3)
    【解决方案9】:

    这个函数将完成将字符串递增到下一个序列的部分

    function increment(str){
    
        var arr = str.split("");
        var c;
        for(var i=arr.length-1; i>=0; i--){
            c = (arr[i].charCodeAt(0)+1)%123;
            arr[i] = String.fromCharCode(c==0?97:c);
            if(c!=0)break;
        }
    return arr.join("");
    }
    

    我正在研究另一种解决方案,以任意数字递增,也可以反向递增。该代码仍然存在一些错误,但只是将其放在这里以获得一些建议。传入负数以反向运行。 对于某些边缘情况,代码会失败,例如:当字符为 'a' 且 num 为负数时

    function jumpTo(str,num){
    
        var arr = str.split("");
        var c;
        for(var i=arr.length-1; i>=0; i--){
            c = (arr[i].charCodeAt(0)+1)%123;
            c += c==0?97+num-1:num-1;
            arr[i] = String.fromCharCode(c==0?97:c);
            if(c!=0)break;
        }
    return arr.join("");
    }
    

    【讨论】:

      【解决方案10】:

      我对此采取了不同的方法,使用一个排列函数递归地生成所有可能的排列,可以使用重复 n 次的数组中的字符生成。代码如下所示。

      //recursively generates permutations
      var permutations = function (li, rep) {
          var i, j, next, ret = [];
          // base cases
          if (rep === 1) {
              return li;
          }
          if (rep <= 0) {
              return [];
          }
          // non-base case
          for (i = 0; i < li.length; i += 1) {
              // generate the next deepest permutation and add
              // the possible beginnings to those
              next = permutations(li, rep-1);
              for (j = 0; j < next.length; j += 1) {
                  ret.push(li[i] + next[j]);
              }
          }
          return ret;
      };
      
      // returns an array of numbers from [start, end)
      // range(10, 14) -> [10, 11, 12, 13]
      var range = function (start, end) {
          var i, ret = [];
          for (i = start; i < end; i+= 1) {
              ret.push(i);
          }
          return ret;
      };
      
      // generates letters ('abcd...')
      var letters = String.fromCharCode.apply(this, range('a'.charCodeAt(0), 'z'.charCodeAt(0)+1));
      
      // calls the function itself, and .join's it into a string
      document.body.innerHTML = (permutations(letters, 3)).join(' ');

      【讨论】:

        【解决方案11】:

        我只想为@procrastinator 提供一个替代答案(因为我无法对答案发表评论,因为我在 Stackoverflow 上没有足够的分数)。他的回答似乎是最通用的方法,但我不禁注意到,在“z”之后出现“ba”,而 op 期望它是“aa”。此外,这遵循 Excel 如何命名它的列。

        这里是更正的代码:

        function s2n(s) {
            var pow, n = 0, i = 0;
            while (i++ < s.length) {
                pow = Math.pow(26, s.length - i);
                var charCode = s.charCodeAt(i - 1) - 96;
                n += charCode * pow;
            }
            return n;
        }
        
        function n2s(n) {
            var s = '';  
            var reduce = false;
        
            if (n === undefined) {
                n = 0;
            } else {
                n--;
            }
            while (n !== undefined) {
                s = String.fromCharCode(97 + n % 26) + s;
                n = Math.floor(n / 26);
                if (n === 0) {
                    n = undefined;
                } else {
                    n--;
                }
            }
            return s;
        }
        

        不是从 0 开始,而是将 1 视为“a”,将 26 视为“z”,将 27 视为“aa”,依此类推。

        【讨论】:

          【解决方案12】:

          获取 A-Z、AA-ZZ、AAA-ZZZ 等,直到循环次数结束。

          function createList(maxCycles) {
            if (typeof maxCycles != "number") {
              console.log("number expected");
              return;
            }
          
            const alphaLen = 26;
            const alpha = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
          
            let list = [alpha];
          
            // go through all cycles
            for (let cycleNo = 1; cycleNo < maxCycles; cycleNo++) {
              list[cycleNo] = [];
              pastCollection = list[cycleNo - 1];
              pastLen = pastCollection.length;
          
              for (let i = 0; i < pastLen; i++) {
                for (let j = 0; j < alphaLen; j++) {
                  // use past item then add a letter of the alphabet at the end
                  list[cycleNo].push(pastCollection[i] + alpha[j]);
                }
              }
            }
          
            return list;
          }
          
          (function(maxCycles) {
            console.log(createList(maxCycles));
          })(3);

          【讨论】:

            猜你喜欢
            • 2013-10-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-10-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-30
            相关资源
            最近更新 更多