Count the number of occurrences of a character in a string in Javascript
我需要计算一个字符串中一个字符出现的次数。
例如,假设我的字符串包含:
1 | var mainStr ="str1,str2,str3,str4"; |
我想找出逗号
我还需要验证每个字符串,例如str1、str2、str3或str4,不应超过15个字符。
我已经更新了这个答案。我更喜欢使用火柴的想法,但它比较慢:
1 2 3 | console.log(("str1,str2,str3,str4".match(/,/g) || []).length); //logs 3 console.log(("str1,str2,str3,str4".match(new RegExp("str","g")) || []).length); //logs 4 |
杰西德
如果事先知道要搜索的内容,请使用正则表达式文本;否则,可以使用
我在2009年给出的原始答案如下。它不必要地创建了一个数组,但使用拆分更快(截至2014年9月)。我是矛盾的,如果我真的需要速度,毫无疑问我会使用分割,但我更喜欢使用匹配。
旧答案(2009年起):
如果您要查找逗号:
1 | (mainStr.split(",").length - 1) //3 |
如果你在找Str
1 | (mainStr.split("str").length - 1) //4 |
无论是在@lo的答案中,还是在我自己愚蠢的JSPerf测试中,分割都是以速度进行的,至少在chrome中是这样,但是再次创建额外的数组似乎并不明智。
至少有四种方法。最好的选择,也应该是最快的-由于本地regex引擎-放在顶部。jspef.com目前已关闭,否则我将向您提供性能统计信息。
更新:请在这里找到性能测试,并自己运行它们,以便贡献您的性能结果。结果的细节将在后面给出。
1。1 2 | ("this is foo bar".match(/o/g)||[]).length //>2 |
2。
1 2 | "this is foo bar".split("o").length-1 //>2 |
不建议拆分。资源匮乏。为每个匹配项分配"array"的新实例。不要通过FileReader对大于100MB的文件进行这种尝试。实际上,您可以使用chrome的profiler选项很容易地观察到确切的资源使用情况。
三。1 2 3 4 | var stringsearch ="o" ,str ="this is foo bar"; for(var count=-1,index=-2; index != -1; count++,index=str.indexOf(stringsearch,index+1) ); //>count:2 |
4。
搜索单个字符
1 2 3 4 | var stringsearch ="o" ,str ="this is foo bar"; for(var i=count=0; i<str.length; count+=+(stringsearch===str[i++])); //>count:2 |
更新:
5。元素映射和过滤,由于其整体资源预分配而不是使用pythonian的"生成器",因此不推荐使用。
1 2 3 4 5 6 | var str ="this is foo bar" str.split('').map( function(e,i){ if(e === 'o') return i;} ) .filter(Boolean) //>[9, 10] [9, 10].length //>2 |
分享:我提出了这一要点,目前有8种字符计数方法,因此我们可以直接汇集和分享我们的想法-只是为了好玩,也许还有一些有趣的基准测试:)
网址:https://gist.github.com/2757250
将此函数添加到Sting原型:
1 2 3 4 5 | String.prototype.count=function(c) { var result = 0, i = 0; for(i;i<this.length;i++)if(this[i]==c)result++; return result; }; |
用途:
1 | console.log("strings".count("s")); //2 |
一个快速的谷歌搜索得到了这个(从http://www.codecodex.com/wiki/index.php?title=count_在_a_string_javascript中特定_字符_出现的_个数)
1 2 3 | String.prototype.count=function(s1) { return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length; } |
这样使用:
1 2 | test = 'one,two,three,four' commas = test.count(',') // returns 3 |
我发现在一个非常大的字符串(例如,1000 000个字符长)中搜索字符的最佳方法是使用
1 2 3 | window.count_replace = function (str, schar) { return str.length - str.replace(RegExp(schar), '').length; }; |
您还可以看到另一个JSPerf套件来测试此方法以及在字符串中查找字符的其他方法。
这里有一个类似的解决方案,但它使用
1 2 3 | function countCharacters(char, string) { return string.split('').reduce((acc, ch) => ch === char ? acc + 1: acc, 0) } |
如前所述,
好的,另一个有regexp的-可能不快,但比其他的短,可读性更好,在我的例子中,只需计算
1 | key.replace(/[^_]/g,'').length |
把所有看起来不像你的角色的东西都去掉但是用字符串作为输入看起来不太好
拆分与regexp的性能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var i = 0; var split_start = new Date().getTime(); while (i < 30000) { "1234,453,123,324".split(",").length -1; i++; } var split_end = new Date().getTime(); var split_time = split_end - split_start; i= 0; var reg_start = new Date().getTime(); while (i < 30000) { ("1234,453,123,324".match(/,/g) || []).length; i++; } var reg_end = new Date().getTime(); var reg_time = reg_end - reg_start; alert ('Split Execution time: ' + split_time +" " + 'RegExp Execution time: ' + reg_time +" "); |
我对已接受的答案做了一点改进,它允许检查区分大小写/不区分大小写的匹配,并且是一种附加到字符串对象的方法:
1 2 3 4 | String.prototype.count = function(lit, cis) { var m = this.toString().match(new RegExp(lit, ((cis) ?"gi" :"g"))); return (m != null) ? m.length : 0; } |
要搜索字符串
1 | var amount_of_os = 'I love StackOverflow.com'.count('o'); |
如果我们要使用不区分大小写的匹配再次搜索相同的字符串,您将使用:
1 | var amount_of_os = 'I love StackOverflow.com'.count('o', true); |
这次,
我正在做一个需要子字符串计数器的小项目。搜索错误的短语没有任何结果,但是在编写了自己的实现之后,我偶然发现了这个问题。不管怎样,这是我的方法,它可能比这里的大多数慢,但可能对某人有帮助:
1 2 3 4 5 6 7 8 9 10 11 | function count_letters() { var counter = 0; for (var i = 0; i < input.length; i++) { var index_of_sub = input.indexOf(input_letter, i); if (index_of_sub > -1) { counter++; i = index_of_sub; } } |
http://jsfiddle.net/5zzht/1/
如果您发现此实现失败或不遵循某些标准,请通知我!:)
更新您可能需要替换:
1 | for (var i = 0; i < input.length; i++) { |
用:
1 | for (var i = 0, input_length = input.length; i < input_length; i++) { |
有趣的阅读讨论上述内容:http://www.erichynds.com/blog/javascript-length-property-is-a-stored-value
简单地说,使用split来查找字符串中出现的字符数。
我发现最简单的方法…
示例-
1 2 3 4 5 6 7 | str = 'mississippi'; function find_occurences(str, char_to_count){ return str.split(char_to_count).length - 1; } find_occurences(str, 'i') //outputs 4 |
您还可以将字符串放在其他位置,并像使用
- array.prototype.filter()。
1 2 3 4 | const mainStr = 'str1,str2,str3,str4'; const commas = [...mainStr].filter(l => l === ',').length; console.log(commas); |
或
- array.prototype.reduce()。
1 2 3 4 | const mainStr = 'str1,str2,str3,str4'; const commas = [...mainStr].reduce((a, c) => c === ',' ? ++a : a, 0); console.log(commas); |
如果您使用的是lodash,则.countby方法将执行以下操作:
1 | _.countBy("abcda")['a'] //2 |
此方法也适用于数组:
1 | _.countBy(['ab', 'cd', 'ab'])['ab'] //2 |
下面使用正则表达式来测试长度。testex确保您没有16个或更大的连续非逗号字符。如果它通过了测试,那么它将继续拆分字符串。计算逗号和计算标记减去1一样简单。
1 2 3 4 5 6 7 8 9 | var mainStr ="str1,str2,str3,str4"; var testregex = /([^,]{16,})/g; if (testregex.test(mainStr)) { alert("values must be separated by commas and each may not exceed 15 characters"); } else { var strs = mainStr.split(','); alert("mainStr contains" + strs.length +" substrings separated by commas."); alert("mainStr contains" + (strs.length-1) +" commas."); } |
还有:
1 2 3 4 | function character_count(string, char, ptr = 0, count = 0) { while (ptr = string.indexOf(char, ptr) + 1) {count ++} return count } |
也适用于整数!
1 2 3 4 | s = 'dir/dir/dir/dir/' for(i=l=0;i<s.length;i++) if(s[i] == '/') l++ |
string.split(desiredCharecter.length-1)怎么样
例子:
var str="生活怎么样";var len=str.split("h").length-1;将为上述字符串中的字符"h"提供计数2;
我使用的是node.js v.6.0.0,最快的是带索引的(LoSauer答案中的第三种方法)。
二是:
1 2 3 4 5 6 7 8 | function count(s, c) { var n = 0; for (let x of s) { if (x == c) n++; } return n; } |
这里有一个几乎和split和replace方法一样快的方法,比regex方法(在chrome中)快一点点。
1 2 3 4 5 | var num = 0; for (ch of"str1,str2,str3,str4") { if (ch === ',') num++; } |
我刚刚用节点v7.4对repl.it做了一个非常快速和脏的测试。对于单个字符,循环的标准是最快的:
一些代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | // winner! function charCount1(s, c) { let count = 0; c = c.charAt(0); // we save some time here for(let i = 0; i < s.length; ++i) { if(c === s.charAt(i)) { ++count; } } return count; } function charCount2(s, c) { return (s.match(new RegExp(c[0], 'g')) || []).length; } function charCount3(s, c) { let count = 0; for(ch of s) { if(c === ch) { ++count; } } return count; } function perfIt() { const s = 'Hello, World!'; const c = 'o'; console.time('charCount1'); for(let i = 0; i < 10000; i++) { charCount1(s, c); } console.timeEnd('charCount1'); console.time('charCount2'); for(let i = 0; i < 10000; i++) { charCount2(s, c); } console.timeEnd('charCount2'); console.time('charCount3'); for(let i = 0; i < 10000; i++) { charCount2(s, c); } console.timeEnd('charCount3'); } |
几次跑步的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | perfIt() charCount1: 3.843ms charCount2: 11.614ms charCount3: 11.470ms => undefined perfIt() charCount1: 3.006ms charCount2: 8.193ms charCount3: 7.941ms => undefined perfIt() charCount1: 2.539ms charCount2: 7.496ms charCount3: 7.601ms => undefined perfIt() charCount1: 2.654ms charCount2: 7.540ms charCount3: 7.424ms => undefined perfIt() charCount1: 2.950ms charCount2: 9.445ms charCount3: 8.589ms |
我知道这可能是一个古老的问题,但我有一个简单的解决方案,适用于JavaScript的低级初学者。
作为一个初学者,我只能理解这个问题的一些解决方案,所以我使用两个嵌套的for循环来对照字符串中的其他每个字符检查每个字符,为找到的每个字符增加一个等于该字符的计数变量。
我创建了一个新的空白对象,其中每个属性键都是一个字符,值是每个字符在字符串中出现的次数(计数)。
示例函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function countAllCharacters(str) { var obj = {}; if(str.length!==0){ for(i=0;i<str.length;i++){ var count = 0; for(j=0;j<str.length;j++){ if(str[i] === str[j]){ count++; } } if(!obj.hasOwnProperty(str[i])){ obj[str[i]] = count; } } } return obj; } |
最快的方法似乎是通过索引运算符:
1 2 3 4 5 6 7 8 9 10 11 | function charOccurances (str, char) { for (var c = 0, i = 0, len = str.length; i < len; ++i) { if (str[i] == char) { ++c; } } return c; } |
用途:
1 | charOccurances('example/path/script.js', '/') == 2 |
或者作为原型函数:
1 2 3 4 5 6 7 8 9 10 11 | String.prototype.charOccurances = function (char) { for (var c = 0, i = 0, len = this.length; i < len; ++i) { if (this[i] == char) { ++c; } } return c; } |
用途:
1 | charOccurances('example/path/script.js', '/') == 2 |
我相信你会发现下面的解决方案是非常短,非常快,能够处理非常长的字符串,能够支持多字符搜索,防错,并能够处理空字符串搜索。
1 2 3 4 5 6 7 8 9 10 | function substring_count(source_str, search_str, index) { source_str +="", search_str +=""; var count = -1, index_inc = Math.max(search_str.length, 1); index = (+index || 0) - index_inc; do { ++count; index = source_str.indexOf(search_str, index + index_inc); } while (~index); return count; } |
示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 | console.log(substring_count("Lorem ipsum dolar un sit amet.","m")) function substring_count(source_str, search_str, index) { source_str +="", search_str +=""; var count = -1, index_inc = Math.max(search_str.length, 1); index = (+index || 0) - index_inc; do { ++count; index = source_str.indexOf(search_str, index + index_inc); } while (~index); return count; } |
上面的代码修复了Jakub Wawszczyk的主要性能缺陷,即使在indexof说没有匹配项,并且他的版本本身也不工作,因为他忘记提供函数输入参数。
我的解决方案:
1 2 3 4 | function countOcurrences(str, value){ var regExp = new RegExp(value,"gi"); return str.match(regExp) ? str.match(regExp).length : 0; } |
我的Ramda JS解决方案:
1 2 3 4 5 6 7 8 9 | const testString = 'somestringtotest' const countLetters = R.compose( R.map(R.length), R.groupBy(R.identity), R.split('') ) countLetters(testString) |
链接到RePL。
如果字符在字符串的开头,则leo sauers答案中的第五个方法失败。例如
1 2 3 4 5 | var needle ='A', haystack = 'AbcAbcAbc'; haystack.split('').map( function(e,i){ if(e === needle) return i;} ) .filter(Boolean).length; |
将给出2而不是3,因为筛选函数布尔值为0时给出了false。
其他可能的过滤功能:
1 2 3 4 5 | haystack.split('').map(function (e, i) { if (e === needle) return i; }).filter(function (item) { return !isNaN(item); }).length; |
1 2 3 4 5 6 7 8 | var a ="acvbasbb"; var b= {}; for (let i=0;i<a.length;i++){ if((a.match(new RegExp(a[i],"g"))).length > 1){ b[a[i]]=(a.match(new RegExp(a[i],"g"))).length; } } console.log(b); |
在JavaScript中,您可以使用上面的代码来获取字符串中出现的字符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var i = 0; var split_start = new Date().getTime(); while (i < 30000) { "1234,453,123,324".split(",").length -1; i++; } var split_end = new Date().getTime(); var split_time = split_end - split_start; i= 0; var reg_start = new Date().getTime(); while (i < 30000) { ("1234,453,123,324".match(/,/g) || []).length; i++; } var reg_end = new Date().getTime(); var reg_time = reg_end - reg_start; alert ('Split Execution time: ' + split_time +" " + 'RegExp Execution time: ' + reg_time +" "); |