【问题标题】:How to get the nth occurrence in a string?如何获取字符串中的第 n 次出现?
【发布时间】:2013-01-06 23:16:07
【问题描述】:

我想得到2nd 出现ABC 的起始位置,如下所示:

var string = "XYZ 123 ABC 456 ABC 789 ABC";
getPosition(string, 'ABC', 2) // --> 16

你会怎么做?

【问题讨论】:

  • 第二次出现还是最后一次出现? :)
  • 对不起,我不是在寻找最后一个索引。我正在寻找nth 出现的起始位置,在本例中是第二个。

标签: javascript


【解决方案1】:

const string = "XYZ 123 ABC 456 ABC 789 ABC";

function getPosition(string, subString, index) {
  return string.split(subString, index).join(subString).length;
}

console.log(
  getPosition(string, 'ABC', 2) // --> 16
)

【讨论】:

  • 我其实不喜欢这个答案。给定一个无限长度的输入,它不必要地创建一个无限长度的数组,然后将其中的大部分丢弃。将fromIndex 参数迭代使用到String.indexOf 会更快、更有效
  • function getPosition(str, m, i) { return str.split(m, i).join(m).length; }
  • 如果您指定每个参数的含义,我会很好。
  • @Foreever 我已经简单实现了OP定义的功能
  • 如果有 i 出现 m,这将为您提供字符串的长度。也就是说,getPosition("aaaa","a",5) 给出了4getPosition("aaaa","a",72) 也是如此!我认为在这些情况下你想要-1。 var ret = str.split(m, i).join(m).length; return ret >= str.length ? -1 : ret; 您可能还想用return ret >= str.length || i <= 0 ? -1 : ret; 捕获i <= 0
【解决方案2】:

您也可以使用字符串 indexOf 而不创建任何数组。

第二个参数是开始寻找下一个匹配的索引。

function nthIndex(str, pat, n){
    var L= str.length, i= -1;
    while(n-- && i++<L){
        i= str.indexOf(pat, i);
        if (i < 0) break;
    }
    return i;
}

var s= "XYZ 123 ABC 456 ABC 789 ABC";

nthIndex(s,'ABC',3)

/*  returned value: (Number)
24
*/

【讨论】:

  • 我喜欢这个版本,因为有长度缓存并且没有扩展字符串原型。
  • 根据jsperf,这种方法比接受的答案快得多
  • i 的递增可以减少混淆:var i; for (i = 0; n &gt; 0 &amp;&amp; i !== -1; n -= 1) { i = str.indexOf(pat, /* fromIndex */ i ? (i + 1) : i); } return i;
  • 我更喜欢这个答案而不是 accepted 答案,因为当我测试不存在的第二个实例时,另一个答案返回了这个返回的第一个字符串的长度 - 1.投赞成票,谢谢。
  • 这不是 JS 的内置功能,这很荒谬。
【解决方案3】:

根据 kennebec 的回答,我创建了一个原型函数,如果未找到第 n 次出现,它将返回 -1 而不是 0。

String.prototype.nthIndexOf = function(pattern, n) {
    var i = -1;

    while (n-- && i++ < this.length) {
        i = this.indexOf(pattern, i);
        if (i < 0) break;
    }

    return i;
}

【讨论】:

  • 从不 使用驼峰命名法,因为本机功能的最终适应可能会无意中被此原型覆盖。在这种情况下,我建议使用所有小写字母和下划线(URL 的破折号):String.prototype.nth_index_of。即使您认为自己的名字足够独特和疯狂,世界也会证明它可以而且会做得更疯狂。
  • 特别是在做原型设计时。当然,没有人可以使用 that 特定的方法名称,尽管允许自己这样做会养成一个坏习惯。一个不同但很关键的例子:在执行 SQL INSERT总是 将数据括起来,因为mysqli_real_escape_string 没有 防止单引号黑客攻击。许多专业编码不仅要养成良好的习惯,还要了解为什么这些习惯很重要。 :-)
  • 不要扩展字符串原型。
【解决方案4】:

因为递归总是答案。

function getPosition(input, search, nth, curr, cnt) {
    curr = curr || 0;
    cnt = cnt || 0;
    var index = input.indexOf(search);
    if (curr === nth) {
        if (~index) {
            return cnt;
        }
        else {
            return -1;
        }
    }
    else {
        if (~index) {
            return getPosition(input.slice(index + search.length),
              search,
              nth,
              ++curr,
              cnt + index + search.length);
        }
        else {
            return -1;
        }
    }
}

【讨论】:

【解决方案5】:

这是我的解决方案,它只是遍历字符串直到找到 n 匹配:

String.prototype.nthIndexOf = function(searchElement, n, fromElement) {
    n = n || 0;
    fromElement = fromElement || 0;
    while (n > 0) {
        fromElement = this.indexOf(searchElement, fromElement);
        if (fromElement < 0) {
            return -1;
        }
        --n;
        ++fromElement;
    }
    return fromElement - 1;
};

var string = "XYZ 123 ABC 456 ABC 789 ABC";
console.log(string.nthIndexOf('ABC', 2));

>> 16

【讨论】:

    【解决方案6】:

    此方法创建一个函数,该函数调用存储在数组中的第 n 次出现的索引

    function nthIndexOf(search, n) { 
        var myArray = []; 
        for(var i = 0; i < myString.length; i++) { //loop thru string to check for occurrences
            if(myStr.slice(i, i + search.length) === search) { //if match found...
                myArray.push(i); //store index of each occurrence           
            }
        } 
        return myArray[n - 1]; //first occurrence stored in index 0 
    }
    

    【讨论】:

    • 我认为您在上面的代码中没有定义 myString,并且不确定 myStr === myString 是否?
    【解决方案7】:

    更短的方式,我认为更容易,不会创建不必要的字符串。

    const findNthOccurence = (string, nth, char) => {
      let index = 0
      for (let i = 0; i < nth; i += 1) {
        if (index !== -1) index = string.indexOf(char, index + 1)
      }
      return index
    }
    

    【讨论】:

    • 如果字符位于字符串的开头/结尾,此函数在某些情况下会为我提供无效索引。
    【解决方案8】:

    使用indexOf递归

    首先检查传递的第 n 个位置是否大于子字符串出现的总数。如果通过,则递归遍历每个索引,直到找到第 n 个。

    var getNthPosition = function(str, sub, n) {
        if (n > str.split(sub).length - 1) return -1;
        var recursePosition = function(n) {
            if (n === 0) return str.indexOf(sub);
            return str.indexOf(sub, recursePosition(n - 1) + 1);
        };
        return recursePosition(n);
    };
    

    【讨论】:

      【解决方案9】:
      function getStringReminder(str, substr, occ) {
         let index = str.indexOf(substr);
         let preindex = '';
         let i = 1;
         while (index !== -1) {
            preIndex = index;
            if (occ == i) {
              break;
            }
            index = str.indexOf(substr, index + 1)
            i++;
         }
         return preIndex;
      }
      console.log(getStringReminder('bcdefgbcdbcd', 'bcd', 3));
      

      【讨论】:

        【解决方案10】:

        一个简单的解决方案,只需添加字符串、字符和 idx:

        function getCharIdx(str,char,n){
          let r = 0
          for (let i = 0; i<str.length; i++){
            if (str[i] === char){
              r++
              if (r === n){
                return i
              }
        
            }
           
          }
        }
        

        【讨论】:

          【解决方案11】:

          我也需要一个可以从字符串末尾搜索的函数,所以我写了这个:

          function getPos(str, char, index, backwards) {
            var split = str.split(char);
            var result = 0;
            var done = false;
          
            split.forEach(function (item, i) {
              if (done) {return}
              result += item.length
              if (!backwards && i === index) {
                done = true
                return
              } else if (backwards && i === split.length - index - 2) {
                done = true
                return
              }  
              result += char.length
            })
            return result
          }
          

          用法:

          getPos('x x x', 'x', 1, false) // 2
          getPos('x x x', 'x', 0, true) // 4
          

          【讨论】:

            【解决方案12】:

            使用String.indexOf:

            var stringToMatch = "XYZ 123 ABC 456 ABC 789 ABC";
            
            function yetAnotherGetNthOccurance(string, seek, occurance) {
                var index = 0, i = 1;
            
                while (index !== -1) {
                    index = string.indexOf(seek, index + 1);
                    if (occurance === i) {
                       break;
                    }
                    i++;
                }
                if (index !== -1) {
                    console.log('Occurance found in ' + index + ' position');
                }
                else if (index === -1 && i !== occurance) {
                    console.log('Occurance not found in ' + occurance + ' position');
                }
                else {
                    console.log('Occurance not found');
                }
            }
            
            yetAnotherGetNthOccurance(stringToMatch, 'ABC', 2);
            // Output: Occurance found in 16 position
            
            yetAnotherGetNthOccurance(stringToMatch, 'ABC', 20);
            // Output: Occurance not found in 20 position
            
            yetAnotherGetNthOccurance(stringToMatch, 'ZAB', 1)
            // Output: Occurance not found
            

            【讨论】:

              【解决方案13】:

              我正在为 StackOverflow 上的另一个问题使用以下代码,并认为它可能适合这里。函数 printList2 允许使用正则表达式并按顺序列出所有出现的事件。 (printList 是对早期解决方案的尝试,但在许多情况下都失败了。)

              <html>
              <head>
              <title>Checking regex</title>
              <script>
              var string1 = "123xxx5yyy1234ABCxxxabc";
              var search1 = /\d+/;
              var search2 = /\d/;
              var search3 = /abc/;
              function printList(search) {
                 document.writeln("<p>Searching using regex: " + search + " (printList)</p>");
                 var list = string1.match(search);
                 if (list == null) {
                    document.writeln("<p>No matches</p>");
                    return;
                 }
                 // document.writeln("<p>" + list.toString() + "</p>");
                 // document.writeln("<p>" + typeof(list1) + "</p>");
                 // document.writeln("<p>" + Array.isArray(list1) + "</p>");
                 // document.writeln("<p>" + list1 + "</p>");
                 var count = list.length;
                 document.writeln("<ul>");
                 for (i = 0; i < count; i++) {
                    document.writeln("<li>" +  "  " + list[i] + "   length=" + list[i].length + 
                        " first position=" + string1.indexOf(list[i]) + "</li>");
                 }
                 document.writeln("</ul>");
              }
              function printList2(search) {
                 document.writeln("<p>Searching using regex: " + search + " (printList2)</p>");
                 var index = 0;
                 var partial = string1;
                 document.writeln("<ol>");
                 for (j = 0; j < 100; j++) {
                     var found = partial.match(search);
                     if (found == null) {
                        // document.writeln("<p>not found</p>");
                        break;
                     }
                     var size = found[0].length;
                     var loc = partial.search(search);
                     var actloc = loc + index;
                     document.writeln("<li>" + found[0] + "  length=" + size + "  first position=" + actloc);
                     // document.writeln("  " + partial + "  " + loc);
                     partial = partial.substring(loc + size);
                     index = index + loc + size;
                     document.writeln("</li>");
                 }
                 document.writeln("</ol>");
              
              }
              </script>
              </head>
              <body>
              <p>Original string is <script>document.writeln(string1);</script></p>
              <script>
                 printList(/\d+/g);
                 printList2(/\d+/);
                 printList(/\d/g);
                 printList2(/\d/);
                 printList(/abc/g);
                 printList2(/abc/);
                 printList(/ABC/gi);
                 printList2(/ABC/i);
              </script>
              </body>
              </html>

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-09-16
                • 1970-01-01
                • 2014-08-08
                • 1970-01-01
                • 2016-07-25
                • 2011-02-04
                • 2021-04-07
                相关资源
                最近更新 更多