ChatGPT解决这个技术问题 Extra ChatGPT

如何计算字符串中出现的字符串?

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

var temp = "This is a string.";
alert(temp.count("is")); //should output '2'
这取决于您是否接受重叠实例,例如 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

G
Govind Rai

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

var temp = "这是一个字符串。"; var count = (temp.match(/is/g) || []).length;控制台.log(计数);

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

var temp = "你好世界!"; var count = (temp.match(/is/g) || []).length;控制台.log(计数);


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

单元测试

https://jsfiddle.net/Victornpb/5axuh96u/

基准

我做了一个基准测试,我的函数比gumbo发布的正则表达式匹配函数快10倍以上。在我的测试字符串中,长度为 25 个字符。出现 2 次字符“o”。我在 Safari 中执行了 1 000 000 次。 Safari 5.1 Benchmark> 总执行时间:5617 ms (regexp) Benchmark> 总执行时间:881 ms(我的函数快 6.4 倍) Firefox 4 Benchmark> 总执行时间:8547 ms (Rexexp) Benchmark> 总执行时间:634 ms (我的函数快了 13.5 倍)编辑:我对缓存子字符串长度所做的更改添加了对字符串的类型转换。添加了可选的“allowOverlapping”参数修复了“”空子字符串大小写的正确输出。

要旨

https://gist.github.com/victornpb/7736865


我在 Safari 5 中重复了这个测试,并用一个小的 (100b) 字符串得到了类似的结果,但是对于一个更大的字符串 (16kb),正则表达式对我来说运行得更快。对于一次迭代(不是 1,000,000 次),无论如何差异都不到一毫秒,所以我的投票投给了正则表达式。
@ajax333221 我的天啊,你读懂了我的想法,几天前我做了这个改进,我打算编辑我的答案jsperf.com/count-string-occurrence-in-string
好的。完全控制和清晰。也许我是一只老狗,但是当它起作用时,“老派”并不是一件坏事!
我在这里找到了您的代码:success-equation.com/mind_reader.html。真的很好,程序员介意在那里放一个参考。
@DanielZuzevich 它将强制类型为 String,以防您执行 occurrences(11,1) //2 并且它仍然可以工作。 (这样做比检查类型和调用 toString() 更快)
а
аlex dykyі

函数 countInstances(string, word) { return string.split(word).length - 1; } console.log(countInstances("这是一个字符串", "is"))


@Antal - 看起来像以前的 chrome 测试版中的一个错误,在更新到最新版本后可以工作,但我仍然会避开这种方法。
这对我来说似乎是一个完全有效的解决方案。
R
Ruslan López

你可以试试这个:

var theString = "这是一个字符串。"; console.log(theString.split("is").length - 1);


R
Ruslan López

我的解决方案:

var temp = "这是一个字符串。";函数 countOcurrences(str, value) { var regExp = new RegExp(value, "gi"); return (str.match(regExp) || []).length; } console.log(countOcurrences(temp, 'is'));


也许最好返回 (str.match(regExp) || []).length;这样你就不会两次评估正则表达式?
您还需要转义您的字符串或 countOcurrences('Hello...','.')==8 而不是 3
w
webXL

您可以使用 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;
F
Faraz Kelhini

非正则表达式版本:

var string = '这是一个字符串', searchFor = 'is', count = 0, pos = string.indexOf(searchFor); while (pos > -1) { ++count; pos = string.indexOf(searchFor, ++pos); } 控制台日志(计数); // 2


1. 仅用于单字符搜索,太微妙 2. 甚至 OP 都要求出现 is
这可能是这里最快的实现,但如果将“++pos”替换为“pos+=searchFor.length”会更快
A
Andrew Myers

只是打代码打 Rebecca Chernoffsolution :-)

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

S
Sunil Garg

String.prototype.Count = function (find) { return this.split(find).length - 1; } console.log("这是一个字符串。".Count("is"));

这将返回 2。


I
Ismael Miguel

这是最快的功能!

为什么更快?

不逐字符检查(有 1 个例外)

使用 while 并递增 1 var(字符计数 var)与 for 循环检查长度并递增 2 var(通常是 var i 和带有字符计数的 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 的长度确实对速度有影响。你可以测试一下。
R
Ruslan López

var temp = "这是一个字符串。"; console.log((temp.match(new RegExp("is", "g")) || []).length);


R
Ruslan López

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

例子:

var index = "这是一个字符串".indexOf("is");控制台.log(索引); var length = "这是一个字符串".match(/[az]/g).length; // 其中 [az] 是一个正则表达式通配符表达式,这就是它较慢的原因 console.log(length);


H
H S Progr

一种简单的方法是将字符串拆分为所需的单词,即我们要计算出现次数的单词,然后从部分数中减去 1:

function checkOccurences(string, word) {
      return string.split(word).length - 1;
}
const text="Let us see. see above, see below, see forward, see backward, see left, see right until we will be right"; 
const count=countOccurences(text,"see "); // 2

J
Jason Larke

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

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

R
Roney Michael
       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 以了解分步说明。


C
Community

基于上面的@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;
}

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


b
bcherny

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

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

M
Meghendra S Yadav

试试看

<?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>

J
Jorge Alberto

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

var temp = "这是一个字符串。"; var count = (temp.split('is').length - 1);警报(计数);


B
BaseZen

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

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

d
dimButTries

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

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

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

let strToCheck = RegExp('is', 'g') let matchesReg = "这是一个字符串。".matchAll(strToCheck) console.log(Array.from(matchesReg).length) // 2


T
Tushar Shukla

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

var search_value = "这是一个假句子!"; var 字母 = 'a'; /*可以接受任何字母,如果有人想动态使用这个变量,请放入一个var*/ letter = letter && "string" === typeof letter ?信 : ””;变量计数; for (var i = count = 0; i < search_value.length; count += (search_value[i++] == letter));控制台.log(计数);

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


m
mendezcode
 function substrCount( str, x ) {
   let count = -1, pos = 0;
   do {
     pos = str.indexOf( x, pos ) + 1;
     count++;
   } while( pos > 0 );
   return count;
 }

f
fahrenheit317

你可以试试这个

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

S
SherylHohman

我们可以使用js的split函数,它的长度减1就是出现的次数。

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

欢迎。 SO 的工作方式与论坛不同。 SO 的设计使得好的答案应该被投票,而不是重复。您建议的答案已经存在,因此您应该对其进行投票。也有在其基础上使用相同概念的答案,但也考虑更细微的解释(例如,sss 中的 ss 应该算作 1 还是 2?)。因此,如果您愿意,也可以投票赞成。对于入职培训,请阅读“如何回答”和帮助部分中的“如何提问”主题,链接到每个页面的顶部。我们很感激 &期待您未来的贡献。
也就是说,非常适合以简洁、清晰的方式发布,并试图提供解释,而许多最古老的答案都未能做到这一点。需要明确的是,在 SO 上不鼓励他们仅使用代码的答案(尽管当时并不总是很好地执行)。期待在未来看到更多。
K
Kamal

var countInstances = 函数(主体,目标){ var globalcounter = 0; var concatstring = ''; for(var i=0,j=target.length;i 2 console.log( countInstances('ababa', 'aba') ); // ==> 2 console.log( countInstances('aaabbb', 'ab') ); // ==> 1


C
Clean Code Studio

substr_count 从 php 转换为 Javascript

Locutus(将 Php 转换为 JS 的包)

substr_count(官网,下面复制代码)

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 函数的翻译


b
b_rop

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

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

函数 subStringCount(ustring, countChar){ var correspCount = 0; var 对应 = 假;变量数量 = 0; var prevChar = null; for(var i=0; i!=ustring.length; i++){ if(ustring.charAt(i) == countChar.charAt(0) && corresp == false){ corresp = true;对应计数 += 1; if(correspCount == countChar.length){ 数量+=1;对应=假;对应计数 = 0; } prevChar = 1; } else if(ustring.charAt(i) == countChar.charAt(prevChar) && corresp == true){ correspCount += 1; if(correspCount == countChar.length){ 数量+=1;对应=假;对应计数 = 0;上一个字符 = 空; }else{ prevChar += 1 ; } }else{ 对应 = 假;对应计数 = 0; } } 返回金额; } console.log(subStringCount('Hello World, Hello World', 'll'));


S
Samruddh Shah

var str = 'stackoverflow'; var arr = Array.from(str);控制台.log(arr); for (let a = 0; a <= arr.length; a++) { var temp = arr[a];变量 c = 0; for (let b = 0; b <= arr.length; b++) { if (temp === arr[b]) { c++; } } console.log(`${arr[a]} 计入 ${c}`) }


请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。带有解释的答案通常更有帮助,质量更好,并且更有可能吸引赞成票
M
Michel

第二次迭代较少(仅当子字符串的第一个字母匹配时)但仍使用 2 for 循环:

   function findSubstringOccurrences(str, word) {
        let occurrences = 0;
        for(let i=0; i<str.length; i++){
            if(word[0] === str[i]){ // to make it faster and iterate less
                for(let j=0; j<word.length; j++){
                    if(str[i+j] !== word[j]) break;
                    if(j === word.length - 1) occurrences++;
                }
            }
        }
        return occurrences;
    }
    
    console.log(findSubstringOccurrences("jdlfkfomgkdjfomglo", "omg"));