【问题标题】:How to count string occurrence in string?如何计算字符串中出现的字符串?
【发布时间】:2011-04-29 21:56:03
【问题描述】:

如何计算特定字符串在另一个字符串中出现的次数。例如,这就是我在 Javascript 中尝试做的事情:

var temp = "This is a string.";
alert(temp.count("is")); //should output '2'

【问题讨论】:

  • 这取决于你是否接受 overlapping 实例,例如var t = "sss";上面的字符串中有多少子字符串“ss”的实例? 1 还是 2?您是跳过每个实例,还是逐个字符移动指针,寻找子字符串?
  • 此问题答案的改进基准:jsperf.com/string-ocurrence-split-vs-match/2(基于 Kazzkiq 的基准)。
  • 统计字符串中特定单词的总数 JavaScript stackoverflow.com/a/65036248/4752258
  • 这个视频在这里似乎有点模糊 - “Google Coding Interview with A Facebook Software Engineer” - youtube.com/watch?v=PIeiiceWe_w

标签: javascript regex string


【解决方案1】:

正则表达式中的gglobal 的缩写)表示要搜索整个字符串,而不是只查找第一个匹配项。这匹配is 两次:

var temp = "This is a string.";
var count = (temp.match(/is/g) || []).length;
console.log(count);

并且,如果没有匹配,则返回0

var temp = "Hello World!";
var count = (temp.match(/is/g) || []).length;
console.log(count);

【讨论】:

  • 现代而优雅,但 Vitimtk 的解决方案效率更高。大家觉得他的代码怎么样?
  • 这最好地回答了这个问题。如果有人问“我怎样才能在特殊情况下(没有正则表达式)将这个速度提高 10 倍”,Vitimtk 会赢得这个问题。
  • 谢谢你。如果你没有匹配,我会和count = (str.match(/is/g) || []).length一起处理。
  • 我认为这个答案与问题不匹配,因为它不像用例描述的那样将字符串作为参数来匹配。当然,您可以使用 RegExp 构造函数动态创建正则表达式并传递您要查找的字符串,但在这种情况下,您必须转义所有元字符。在这种情况下,最好使用纯字符串方法。
  • 马特的答案应该在答案中!
【解决方案2】:

function countInstances(string, word) {
   return string.split(word).length - 1;
}
console.log(countInstances("This is a string", "is"))

【讨论】:

  • @Antal - 看起来像以前的 chrome 测试版中的一个错误,更新到最新版本后可以工作,但我仍然会避开这种方法。
  • 这对我来说似乎是一个非常有效的解决方案。
  • @NickCraver 出于好奇,您为什么要避开这种方法? (除了您的测试版浏览器中的错误)
  • @JonnyLin 它会创建不必要的分配,当替代方案没有时您会立即丢弃 - 可能非常大,具体取决于数据。
  • 这是一种非常消耗内存的方法,效率不高,如果要处理的数据过多,则会产生很大的内存压力。
【解决方案3】:

你可以使用match来定义这样的函数:

String.prototype.count = function(search) {
    var m = this.match(new RegExp(search.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "g"));
    return m ? m.length:0;
}

【讨论】:

  • 如果你希望它与 JS 的搜索语义一致,返回行将是 return m ? m.length:-1;
  • 这比上面的其他正则表达式解决方案要好,因为如果要计算出现次数的字符串是“[”或在正则表达式中具有特殊含义的任何内容,它们会导致错误。
【解决方案4】:

只是打代码Rebecca Chernoff's solution :-)

alert(("This is a string.".match(/is/g) || []).length);

【讨论】:

    【解决方案5】:
    /** Function that count occurrences of a substring in a string;
     * @param {String} string               The string
     * @param {String} subString            The sub string to search for
     * @param {Boolean} [allowOverlapping]  Optional. (Default:false)
     *
     * @author Vitim.us https://gist.github.com/victornpb/7736865
     * @see Unit Test https://jsfiddle.net/Victornpb/5axuh96u/
     * @see https://stackoverflow.com/a/7924240/938822
     */
    function occurrences(string, subString, allowOverlapping) {
    
        string += "";
        subString += "";
        if (subString.length <= 0) return (string.length + 1);
    
        var n = 0,
            pos = 0,
            step = allowOverlapping ? 1 : subString.length;
    
        while (true) {
            pos = string.indexOf(subString, pos);
            if (pos >= 0) {
                ++n;
                pos += step;
            } else break;
        }
        return n;
    }
    

    用法

    occurrences("foofoofoo", "bar"); //0
    
    occurrences("foofoofoo", "foo"); //3
    
    occurrences("foofoofoo", "foofoo"); //1
    

    允许重叠

    occurrences("foofoofoo", "foofoo", true); //2
    

    匹配:

      foofoofoo
    1 `----´
    2    `----´
    

    单元测试

    基准测试

    我做了一个基准测试,我的功能超过了 10 次 比gumbo发布的正则表达式匹配函数更快。在我的测试中 字符串长度为 25 个字符。出现 2 次字符“o”。一世 在 Safari 中执行了 1 000 000 次。

    Safari 5.1

    Benchmark> 总执行时间:5617 毫秒(正则表达式)

    Benchmark> 总执行时间:881 毫秒(我的函数快 6.4 倍)

    Firefox 4

    Benchmark> 总执行时间:8547 ms (Rexexp)

    Benchmark> 总执行时间:634 毫秒(我的函数快 13.5 倍)


    编辑:我所做的更改

    • 缓存子串长度

    • 为字符串添加了类型转换。

    • 添加了可选的“allowOverlapping”参数

    • 修正了“”空子字符串大小写的正确输出。

    要点

    【讨论】:

    • 我在 Safari 5 中重复了这个测试,并用一个小的 (100b) 字符串得到了类似的结果,但是对于一个较大的字符串 (16kb),正则表达式对我来说运行得更快。对于一次迭代(不是 1,000,000 次),无论如何差异都不到一毫秒,所以我的投票投给了正则表达式。
    • +1,但是您几乎在每个循环上都检查substring.length,您应该考虑将其缓存在while之外
    • @ajax333221 天​​哪,你读懂了我的想法,几天前我做了这个改进,我打算编辑我​​的答案jsperf.com/count-string-occurrence-in-string
    • 我在这里找到了你的代码:success-equation.com/mind_reader.html。程序员真的很高兴在那里放一个参考。
    • @DanielZuzevich 它将强制类型为 String,以防您执行 occurrences(11,1) //2 并且它仍然可以工作。 (这样做比检查类型和调用 toString() 更快)
    【解决方案6】:

    试试这个:

    function countString(str, search){
        var count=0;
        var index=str.indexOf(search);
        while(index!=-1){
            count++;
            index=str.indexOf(search,index+1);
        }
        return count;
    }
    

    【讨论】:

      【解决方案7】:

      你可以试试这个:

      var theString = "This is a string.";
      console.log(theString.split("is").length - 1);

      【讨论】:

      • +1 是为了简单起见,因为 accordingly to my tests 这个解决方案运行速度比其他解决方案快约 10 倍
      • 例如我有两个“是”你如何得到每个的位置?
      • 正如@Orbit 的回答中所讨论的,人们在旧版本的 Chrome 上得到了不同的结果。使用这种方法我可能会有点谨慎。
      • 您也可以将它与变量一起使用:theString.split(myvar).length - 1 不能使用简单的正则表达式
      • 这是@Orbit 的answer 三年后...
      【解决方案8】:

      我认为正则表达式的目的与indexOf 大不相同。 indexOf 只需找到某个字符串的出现,而在正则表达式中,您可以使用像 [A-Z] 这样的通配符,这意味着它会在单词中找到 any 大写字符,而无需说明实际字符。

      例子:

       var index = "This is a string".indexOf("is");
       console.log(index);
       var length = "This is a string".match(/[a-z]/g).length;
       // where [a-z] is a regex wildcard expression thats why its slower
       console.log(length);

      【讨论】:

        【解决方案9】:

        超级骗子,但我今天需要做这样的事情,后来才想检查一下。对我来说工作得很快。

        String.prototype.count = function(substr,start,overlap) {
            overlap = overlap || false;
            start = start || 0;
        
            var count = 0, 
                offset = overlap ? 1 : substr.length;
        
            while((start = this.indexOf(substr, start) + offset) !== (offset - 1))
                ++count;
            return count;
        };
        

        【讨论】:

          【解决方案10】:

          我的解决方案:

          var temp = "This is a string.";
          
          function countOcurrences(str, value) {
            var regExp = new RegExp(value, "gi");
            return (str.match(regExp) || []).length;
          }
          
          console.log(countOcurrences(temp, 'is'));

          【讨论】:

          • 也许返回 (str.match(regExp) || []).length; 会更好这样你就不会计算两次正则表达式?
          • 你还需要 scape 你的字符串或countOcurrences('Hello...','.')==8 而不是 3
          【解决方案11】:

          这是最快的功能!

          为什么更快?

          • 不逐字符检查(有 1 个例外)
          • 使用 while 并增加 1 个 var(char 计数 var)与 for 循环检查长度并增加 2 个 var(通常是 var i 和一个带有 char 计数的 var)
          • 使用更少的变量
          • 不使用正则表达式!
          • 使用(希望)高度优化的函数
          • 所有操作都尽可能组合在一起,避免由于多个操作而导致速度下降

            String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};
            

          这是一个更慢且更易读的版本:

              String.prototype.timesCharExist = function ( chr ) {
                  var total = 0, last_location = 0, single_char = ( chr + '' )[0];
                  while( last_location = this.indexOf( single_char, last_location ) + 1 )
                  {
                      total = total + 1;
                  }
                  return total;
              };
          

          由于计数器、长变量名和误用 1 个变量,这个比较慢。

          要使用它,您只需这样做:

              'The char "a" only shows up twice'.timesCharExist('a');
          

          编辑:(2013/12/16)

          请勿与 Opera 12.16 或更早版本一起使用!它将比正则表达式解决方案多花费近 2.5 倍!

          在 chrome 上,对于 1,000,000 个字符,此解决方案需要 14 毫秒到 20 毫秒。

          同样数量的正则表达式解决方案需要 11-14 毫秒。

          使用函数(String.prototype 之外)大约需要 10-13 毫秒。

          这里是使用的代码:

              String.prototype.timesCharExist=function(c){var t=0,l=0,c=(c+'')[0];while(l=this.indexOf(c,l)+1)++t;return t};
          
              var x=Array(100001).join('1234567890');
          
              console.time('proto');x.timesCharExist('1');console.timeEnd('proto');
          
              console.time('regex');x.match(/1/g).length;console.timeEnd('regex');
          
              var timesCharExist=function(x,c){var t=0,l=0,c=(c+'')[0];while(l=x.indexOf(c,l)+1)++t;return t;};
          
              console.time('func');timesCharExist(x,'1');console.timeEnd('func');
          

          所有解的结果应该是100,000!

          注意:如果您希望此函数计数超过 1 个字符,请将 where is c=(c+'')[0] 更改为 c=c+''

          【讨论】:

          • 原型就是一个例子!您可以随意使用该功能!你甚至可以这样做: var timesFunctionExist=function(x,c){var t=0,l=0,c=(c+'')[0];while(l=x.indexOf(c,l)+1 )++t;返回t}); alert(timesCharExist('字符 "a" 只出现两次','a'));! (这会加快一点,因为我不会弄乱原型)。如果你认为我错了,为什么不在向我扔石头之前表现出来?向我证明我的功能很糟糕,我会接受它。给我看一个测试用例。 vars 的长度确实对速度有影响。你可以测试一下。
          【解决方案12】:

          试试看

          <?php 
          $str = "33,33,56,89,56,56";
          echo substr_count($str, '56');
          ?>
          
          <script type="text/javascript">
          var temp = "33,33,56,89,56,56";
          var count = temp.match(/56/g);  
          alert(count.length);
          </script>
          

          【讨论】:

            【解决方案13】:

            非正则表达式版本:

             var string = 'This is a string',
                searchFor = 'is',
                count = 0,
                pos = string.indexOf(searchFor);
            
            while (pos > -1) {
                ++count;
                pos = string.indexOf(searchFor, ++pos);
            }
            
            console.log(count);   // 2

            【讨论】:

            • 1.它仅用于单字符搜索,太微妙 2. 甚至 OP 都要求 is 出现
            • 这可能是这里最快的实现,但如果将“++pos”替换为“pos+=searchFor.length”会更快
            【解决方案14】:
                   var myString = "This is a string.";
                    var foundAtPosition = 0;
                    var Count = 0;
                    while (foundAtPosition != -1)
                    {
                        foundAtPosition = myString.indexOf("is",foundAtPosition);
                        if (foundAtPosition != -1)
                        {
                            Count++;
                            foundAtPosition++;
                        }
                    }
                    document.write("There are " + Count + " occurrences of the word IS");
            

            请参阅:- count a substring appears in the string 以了解分步说明。

            【讨论】:

              【解决方案15】:

              对于将来找到此线程的任何人,请注意,如果您对其进行概括,接受的答案将不会总是返回正确的值,因为它会阻塞像 $. 这样的正则表达式运算符。这是一个更好的版本,可以处理任何针:

              function occurrences (haystack, needle) {
                var _needle = needle
                  .replace(/\[/g, '\\[')
                  .replace(/\]/g, '\\]')
                return (
                  haystack.match(new RegExp('[' + _needle + ']', 'g')) || []
                ).length
              }
              

              【讨论】:

                【解决方案16】:

                var temp = "This is a string.";
                console.log((temp.match(new RegExp("is", "g")) || []).length);

                【讨论】:

                  【解决方案17】:

                  以@Vittim.us 上面的回答为基础。我喜欢他的方法给我的控制,使其易于扩展,但我需要添加不区分大小写并将匹配限制为支持标点符号的整个单词。 (例如“洗澡”在“洗澡”中。但不是“洗澡”)

                  标点正则表达式来自:https://stackoverflow.com/a/25575009/497745 (How can I strip all punctuation from a string in JavaScript using regex?)

                  function keywordOccurrences(string, subString, allowOverlapping, caseInsensitive, wholeWord)
                  {
                  
                      string += "";
                      subString += "";
                      if (subString.length <= 0) return (string.length + 1); //deal with empty strings
                  
                      if(caseInsensitive)
                      {            
                          string = string.toLowerCase();
                          subString = subString.toLowerCase();
                      }
                  
                      var n = 0,
                          pos = 0,
                          step = allowOverlapping ? 1 : subString.length,
                          stringLength = string.length,
                          subStringLength = subString.length;
                  
                      while (true)
                      {
                          pos = string.indexOf(subString, pos);
                          if (pos >= 0)
                          {
                              var matchPos = pos;
                              pos += step; //slide forward the position pointer no matter what
                  
                              if(wholeWord) //only whole word matches are desired
                              {
                                  if(matchPos > 0) //if the string is not at the very beginning we need to check if the previous character is whitespace
                                  {                        
                                      if(!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?@\[\]^_`{|}~]/.test(string[matchPos - 1])) //ignore punctuation
                                      {
                                          continue; //then this is not a match
                                      }
                                  }
                  
                                  var matchEnd = matchPos + subStringLength;
                                  if(matchEnd < stringLength - 1)
                                  {                        
                                      if (!/[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&\(\)*+,\-.\/:;<=>?@\[\]^_`{|}~]/.test(string[matchEnd])) //ignore punctuation
                                      {
                                          continue; //then this is not a match
                                      }
                                  }
                              }
                  
                              ++n;                
                          } else break;
                      }
                      return n;
                  }
                  

                  如果您发现错误或改进,请随时修改和重构此答案。

                  【讨论】:

                    【解决方案18】:

                    现在这是我遇到的一个非常古老的线程,但是由于许多人已经提出了他们的答案,所以这是我的,希望通过这个简单的代码来帮助某人。

                    var search_value = "This is a dummy sentence!";
                    var letter = 'a'; /*Can take any letter, have put in a var if anyone wants to use this variable dynamically*/
                    letter = letter && "string" === typeof letter ? letter : "";
                    var count;
                    for (var i = count = 0; i < search_value.length; count += (search_value[i++] == letter));
                    console.log(count);

                    我不确定它是否是最快的解决方案,但我更喜欢它是为了简单且不使用正则表达式(我只是不喜欢使用它们!)

                    【讨论】:

                      【解决方案19】:

                      没有正则表达式的简单版本:

                      var temp = "This is a string.";
                      
                      var count = (temp.split('is').length - 1);
                      
                      alert(count);

                      【讨论】:

                      • 这是@Orbit 的answer 六年后...
                      【解决方案20】:

                      String.prototype.Count = function (find) {
                          return this.split(find).length - 1;
                      }
                      
                      console.log("This is a string.".Count("is"));

                      这将返回 2。

                      【讨论】:

                      • 这是@Orbit 的answer 六年后...
                      【解决方案21】:

                      Leandro Batista 的答案: 只是正则表达式的问题。

                       "use strict";
                       var dataFromDB = "testal";
                       
                        $('input[name="tbInput"]').on("change",function(){
                      	var charToTest = $(this).val();
                      	var howManyChars = charToTest.length;
                      	var nrMatches = 0;
                      	if(howManyChars !== 0){
                      		charToTest = charToTest.charAt(0);
                      		var regexp = new RegExp(charToTest,'gi');
                      		var arrMatches = dataFromDB.match(regexp);
                      		nrMatches = arrMatches ? arrMatches.length : 0;
                      	}
                      		$('#result').html(nrMatches.toString());
                      
                        });
                      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
                      <div class="main">
                      What do you wanna count <input type="text" name="tbInput" value=""><br />
                      Number of occurences = <span id="result">0</span>
                      </div>

                      【讨论】:

                        【解决方案22】:

                        var countInstances = function(body, target) {
                          var globalcounter = 0;
                          var concatstring  = '';
                          for(var i=0,j=target.length;i<body.length;i++){
                            concatstring = body.substring(i-1,j);
                            
                            if(concatstring === target){
                               globalcounter += 1;
                               concatstring = '';
                            }
                          }
                          
                          
                          return globalcounter;
                         
                        };
                        
                        console.log(   countInstances('abcabc', 'abc')   ); // ==> 2
                        console.log(   countInstances('ababa', 'aba')   ); // ==> 2
                        console.log(   countInstances('aaabbb', 'ab')   ); // ==> 1

                        【讨论】:

                          【解决方案23】:

                          没有人会看到这一点,但偶尔带回递归和箭头函数是件好事(双关语是有意的)

                          String.prototype.occurrencesOf = function(s, i) {
                           return (n => (n === -1) ? 0 : 1 + this.occurrencesOf(s, n + 1))(this.indexOf(s, (i || 0)));
                          };
                          

                          【讨论】:

                          • 我看到了这个... :p
                          【解决方案24】:

                          came across this post.

                          let str = 'As sly as a fox, as strong as an ox';
                          
                          let target = 'as'; // let's look for it
                          
                          let pos = 0;
                          while (true) {
                            let foundPos = str.indexOf(target, pos);
                            if (foundPos == -1) break;
                          
                            alert( `Found at ${foundPos}` );
                            pos = foundPos + 1; // continue the search from the next position
                          }
                          

                          同样的算法可以布局更短:

                          let str = "As sly as a fox, as strong as an ox";
                          let target = "as";
                          
                          let pos = -1;
                          while ((pos = str.indexOf(target, pos + 1)) != -1) {
                            alert( pos );
                          }
                          

                          【讨论】:

                            【解决方案25】:

                            substr_count 从 php 转换为 Javascript


                            function substr_count (haystack, needle, offset, length) { 
                              // eslint-disable-line camelcase
                              //  discuss at: https://locutus.io/php/substr_count/
                              // original by: Kevin van Zonneveld (https://kvz.io)
                              // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
                              // improved by: Brett Zamir (https://brett-zamir.me)
                              // improved by: Thomas
                              //   example 1: substr_count('Kevin van Zonneveld', 'e')
                              //   returns 1: 3
                              //   example 2: substr_count('Kevin van Zonneveld', 'K', 1)
                              //   returns 2: 0
                              //   example 3: substr_count('Kevin van Zonneveld', 'Z', 0, 10)
                              //   returns 3: false
                            
                              var cnt = 0
                            
                              haystack += ''
                              needle += ''
                              if (isNaN(offset)) {
                                offset = 0
                              }
                              if (isNaN(length)) {
                                length = 0
                              }
                              if (needle.length === 0) {
                                return false
                              }
                              offset--
                            
                              while ((offset = haystack.indexOf(needle, offset + 1)) !== -1) {
                                if (length > 0 && (offset + needle.length) > length) {
                                  return false
                                }
                                cnt++
                              }
                            
                              return cnt
                            }
                            

                            查看 Locutus 对 Php 的 substr_count 函数的翻译

                            【讨论】:

                              【解决方案26】:
                               function substrCount( str, x ) {
                                 let count = -1, pos = 0;
                                 do {
                                   pos = str.indexOf( x, pos ) + 1;
                                   count++;
                                 } while( pos > 0 );
                                 return count;
                               }
                              

                              【讨论】:

                                【解决方案27】:

                                你可以试试这个

                                let count = s.length - s.replace(/is/g, "").length;
                                

                                【讨论】:

                                  【解决方案28】:

                                  参数: ustring:超集字符串 countChar:子字符串

                                  在 JavaScript 中计算子字符串出现次数的函数:

                                  function subStringCount(ustring, countChar){
                                    var correspCount = 0;
                                    var corresp = false;
                                    var amount = 0;
                                    var prevChar = null;
                                    
                                   for(var i=0; i!=ustring.length; i++){
                                  
                                       if(ustring.charAt(i) == countChar.charAt(0) && corresp == false){
                                         corresp = true;
                                         correspCount += 1;
                                         if(correspCount == countChar.length){
                                           amount+=1;
                                           corresp = false;
                                           correspCount = 0;
                                         }
                                         prevChar = 1;
                                       }
                                       else if(ustring.charAt(i) == countChar.charAt(prevChar) && corresp == true){
                                         correspCount += 1;
                                         if(correspCount == countChar.length){
                                           amount+=1;
                                           corresp = false;
                                           correspCount = 0;
                                           prevChar = null;
                                         }else{
                                           prevChar += 1 ;
                                         }
                                       }else{
                                         corresp = false;
                                         correspCount = 0;
                                       }
                                   } 
                                   return amount;
                                  }
                                  
                                  console.log(subStringCount('Hello World, Hello World', 'll'));

                                  【讨论】:

                                    【解决方案29】:

                                    var str = 'stackoverflow';
                                    var arr = Array.from(str);
                                    console.log(arr);
                                    
                                    for (let a = 0; a <= arr.length; a++) {
                                      var temp = arr[a];
                                      var c = 0;
                                      for (let b = 0; b <= arr.length; b++) {
                                        if (temp === arr[b]) {
                                          c++;
                                        }
                                    
                                      }
                                      console.log(`the ${arr[a]} is counted for ${c}`)
                                    }

                                    【讨论】:

                                    • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助、质量更好,并且更有可能吸引投票
                                    【解决方案30】:

                                    ES2020 提供了一个新的 MatchAll,它可能在这个特定的上下文中有用。

                                    这里我们创建了一个新的正则表达式,请确保您将“g”传递给函数。

                                    使用 Array.from 转换结果并计算长度,根据原始请求者的期望输出返回 2。

                                    let strToCheck = RegExp('is', 'g')
                                    let matchesReg = "This is a string.".matchAll(strToCheck)
                                    console.log(Array.from(matchesReg).length) // 2

                                    【讨论】:

                                      猜你喜欢
                                      • 2012-10-03
                                      • 2014-04-24
                                      • 2010-09-21
                                      • 2020-02-21
                                      • 2012-02-12
                                      相关资源
                                      最近更新 更多