计算Javascript中字符串中字符的出现次数

我需要计算字符串中一个字符的出现次数。

例如,假设我的字符串包含:

var mainStr = "str1,str2,str3,str4";

我想找到逗号,字符的计数,这是3。以及沿着逗号拆分后的单个字符串的计数,这是4。

我还需要验证每个字符串,即str1或str2或str3或str4不应超过15个字符。

971516 次浏览

我更新了这个答案。我更喜欢使用匹配的想法,但它更慢:

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

如果您事先知道要搜索什么,请使用正则表达式文字,如果不知道,您可以使用RegExp构造函数,并传入g标志作为参数。

match返回null没有结果,因此|| []

我在2009年做出的原始答案如下。它不必要地创建了一个数组,但是使用拆分更快(截至2014年9月)。我很矛盾,如果我真的需要速度,毫无疑问我会使用拆分,但我更喜欢使用匹配。

老答案(2009年):

如果你正在寻找逗号:

(mainStr.split(",").length - 1) //3

如果你正在寻找的str

(mainStr.split("str").length - 1) //4

在@Lo的回答和我自己愚蠢的性能测试拆分中,速度都领先,至少在Chrome,但再次创建额外的数组似乎并不明智。

一个快速的谷歌搜索得到了这个(来自http://www.codecodex.com/wiki/index.php?title=Count_the_number_of_occurrences_of_a_specific_character_in_a_string#JavaScript

String.prototype.count=function(s1) {
return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}

像这样使用它:

test = 'one,two,three,four'
commas = test.count(',') // returns 3

下面使用正则表达式来测试长度。testex确保您没有16个或更大的连续非逗号字符。如果它通过测试,则继续拆分字符串。计数逗号就像计数标记减一一样简单。

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.");
}

至少有五种方法。最好的选择,也应该是最快的(由于原生RegEx引擎)放在顶部。

方法1

("this is foo bar".match(/o/g)||[]).length;
// returns 2

方法2

"this is foo bar".split("o").length - 1;
// returns 2

不推荐拆分,因为它资源匮乏。它为每个匹配分配新的数组实例。不要通过FileReader尝试使用>100MB的文件。您可以使用Chrome侧写员选项观察确切的资源使用情况。

方法3

    var stringsearch = "o"
,str = "this is foo bar";
for(var count=-1,index=-2; index != -1; count++,index=str.indexOf(stringsearch,index+1) );
// returns 2

方法4

搜索单个字符

    var stringsearch = "o"
,str = "this is foo bar";
for(var i=count=0; i<str.length; count+=+(stringsearch===str[i++]));
// returns 2

方法5

元素映射和过滤。由于其整体资源预分配而不是使用Python“生成器”,因此不建议这样做:

    var str = "this is foo bar"
str.split('').map( function(e,i){ if(e === 'o') return i;} )
.filter(Boolean)
//>[9, 10]
[9, 10].length
// returns 2

分享: 我做了这个要点,目前有8种字符计数方法,所以我们可以直接汇集和分享我们的想法-只是为了好玩,也许还有一些有趣的基准:)

s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++

我的解决方案:

function countOcurrences(str, value){
var regExp = new RegExp(value, "gi");
return str.match(regExp) ? str.match(regExp).length : 0;
}

我正在做一个需要子字符串计数器的小项目。搜索错误的短语没有给我提供任何结果,但是在编写自己的实现后,我偶然发现了这个问题。无论如何,这是我的方式,它可能比这里的大多数慢,但可能对某人有帮助:

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

请让我知道,如果你发现这个实现失败或不遵循一些标准!:)

更新 您可能需要替换:

    for (var i = 0; i < input.length; i++) {

有:

for (var i = 0, input_length = input.length; i < input_length; i++) {

有趣的阅读讨论上述内容: http://www.erichynds.com/blog/javascript-length-property-is-a-stored-value

我发现在一个非常大的字符串中搜索字符的最佳方法(例如,1 000 000个字符长)是使用replace()方法。

window.count_replace = function (str, schar) {
return str.length - str.replace(RegExp(schar), '').length;
};

您可以看到另一个JSPerf套件来测试此方法以及在字符串中查找字符的其他方法。

将此函数添加到sting原型:

String.prototype.count=function(c) {
var result = 0, i = 0;
for(i;i<this.length;i++)if(this[i]==c)result++;
return result;
};

用法:

console.log("strings".count("s")); //2

我对接受的答案做了一点改进,它允许检查区分大小写/不区分大小写的匹配,并且是附加到字符串对象的方法:

String.prototype.count = function(lit, cis) {
var m = this.toString().match(new RegExp(lit, ((cis) ? "gi" : "g")));
return (m != null) ? m.length : 0;
}

lit是要搜索的字符串(例如'ex'),cis是不区分大小写的,默认为false,它将允许选择不区分大小写的匹配。


要在字符串'I love StackOverflow.com'中搜索小写字母'o',您可以使用:

var amount_of_os = 'I love StackOverflow.com'.count('o');

amount_of_os等于2


如果我们使用不区分大小写的匹配再次搜索相同的字符串,您将使用:

var amount_of_os = 'I love StackOverflow.com'.count('o', true);

这一次,amount_of_os将等于3,因为字符串中的大写O将包含在搜索中。

好的,另一个带有regexp的-可能不是很快,但比其他人更短,更易读,在我的情况下,只是'_'计数

key.replace(/[^_]/g,'').length

删除所有看起来不像你的char的东西 但是用字符串作为输入看起来不太好

string.split怎么样?

示例:

var str="生活如何"; var len=str.split("h").长度-1;将为上述字符串中的字符"h"提供计数2;

我使用Node.jsv.6.0.0,最快的是带索引的方法(Lo Sauer答案中的第三种方法)。

第二个是:

function count(s, c) {
var n = 0;
for (let x of s) {
if (x == c)
n++;
}
return n;
}

Split vs RegExp的性能

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 + "\n" + 'RegExp Execution time: ' + reg_time + "\n");

这是一个类似的解决方案,但它使用Array.prototype.reduce

function countCharacters(char, string) {
return string.split('').reduce((acc, ch) => ch === char ? acc + 1: acc, 0)
}

如前所述,String.prototype.split的工作速度比String.prototype.replace快得多。

我发现的最简单的方法…

例子-

str = 'mississippi';


function find_occurences(str, char_to_count){
return str.split(char_to_count).length - 1;
}


find_occurences(str, 'i') //outputs 4

如果你使用的是洛达什,_方法将执行以下操作:

_.countBy("abcda")['a'] //2

此方法也适用于数组:

_.countBy(['ab', 'cd', 'ab'])['ab'] //2

这里有一个与split()和替换方法一样快的方法,它们比regex方法(在Chrome和Firefox中)快一点。

let num = 0;
let str = "str1,str2,str3,str4";
//Note: Pre-calculating `.length` is an optimization;
//otherwise, it recalculates it every loop iteration.
let len = str.length;
//Note: Don't use a `for (... of ...)` loop, it's slow!
for (let charIndex = 0; charIndex < len; ++charIndex) {
if (str[charIndex] === ',') {
++num;
}
}

我刚刚使用Node v7.4对repl.it做了一个非常快速和肮脏的测试。对于单个字符,循环的标准是最快的:

一些代码

// 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');
}

几次运行的结果

perfIt()
charCount1: 3.301ms
charCount2: 11.652ms
charCount3: 174.043ms
undefined


perfIt()
charCount1: 2.110ms
charCount2: 11.931ms
charCount3: 177.743ms
undefined


perfIt()
charCount1: 2.074ms
charCount2: 11.738ms
charCount3: 152.611ms
undefined


perfIt()
charCount1: 2.076ms
charCount2: 11.685ms
charCount3: 154.757ms
undefined

更新2021-2-10:修复了repl.it演示中的错字

更新2020-Oct-24还是12Node.js的情况(这里自己玩)

如果字符位于字符串的开头,Leo Sauers答案中的第五个方法失败。 例如

var needle ='A',
haystack = 'AbcAbcAbc';


haystack.split('').map( function(e,i){ if(e === needle) return i;} )
.filter(Boolean).length;

将给出2而不是3,因为过滤器函数布尔值为0给出false。

其他可能的过滤功能:

haystack.split('').map(function (e, i) {
if (e === needle) return i;
}).filter(function (item) {
return !isNaN(item);
}).length;

还有一个答案:

function count(string){
const count={}
  

string.split('').forEach(char=>{
count[char] = count[char] ? (count[char]+1) : 1;
})
  

return count
}


console.log(count("abfsdfsddsfdfdsfdsfdsfda"))

我知道这可能是一个老问题,但我为JavaScript的低级初学者提供了一个简单的解决方案。

作为初学者,我只能理解这个问题的一些解决方案,所以我使用了两个嵌套的for循环来检查字符串中的每个字符,为每个找到的字符递增一个计数变量等于该字符。

我创建了一个新的空白对象,其中每个属性键都是一个字符,值是每个字符在字符串中出现的次数(计数)。

示例函数:-

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

我相信你会发现下面的解决方案非常短,非常快,能够处理很长的字符串,能够支持多个字符搜索,防错,并且能够处理空字符串搜索。

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

示例用法:

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的主要性能bug,即使indexOf说没有匹配,他的版本本身也不起作用,因为他忘记给函数输入参数。

最快的方法似乎是通过索引运算符:

function charOccurances (str, char)
{
for (var c = 0, i = 0, len = str.length; i < len; ++i)
{
if (str[i] == char)
{
++c;
}
}
return c;
}


console.log( charOccurances('example/path/script.js', '/') ); // 2

或者作为原型函数:

String.prototype.charOccurances = function (char)
{
for (var c = 0, i = 0, len = this.length; i < len; ++i)
{
if (this[i] == char)
{
++c;
}
}
return c;
}


console.log( 'example/path/script.js'.charOccurances('/') ); // 2

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中,您可以使用上面的代码来获取字符串中字符的出现。

简单地说,使用分裂找出字符串中字符的出现次数。

mainStr.split(',').length//给出4,这是使用分隔符逗号拆分后的字符串数

mainStr.split(',').length - 1//给出3,这是逗号的计数

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 + "\n" + 'RegExp Execution time: ' + reg_time + "\n");

并且有:

function character_count(string, char, ptr = 0, count = 0) {
while (ptr = string.indexOf(char, ptr) + 1) {count ++}
return count
}

也适用于整数!

您还可以休息您的字符串并像使用元素数组一样使用它

const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].filter(l => l === ',').length;


console.log(commas);

const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].reduce((a, c) => c === ',' ? ++a : a, 0);


console.log(commas);

我使用ramda js的解决方案:

const testString = 'somestringtotest'


const countLetters = R.compose(
R.map(R.length),
R.groupBy(R.identity),
R.split('')
)


countLetters(testString)

链接到REPL。

该函数将字符串str作为参数,并计算字符串中每个唯一字符的出现次数。结果为每个字符的键-值对。

var charFoundMap = {};//object defined
for (var i = 0; i < str.length; i++) {


if(!charFoundMap[ str[i] ])  {
charFoundMap[ str[i] ]=1;
}
else
charFoundMap[ str[i] ] +=1;
//if object does not contain this
}
return charFoundMap;


}

这是我的解决方案。在我之前已经发布了很多解决方案。但我喜欢在这里分享我的观点。

const mainStr = 'str1,str2,str3,str4';


const commaAndStringCounter = (str) => {
const commas = [...str].filter(letter => letter === ',').length;
const numOfStr = str.split(',').length;


return `Commas: ${commas}, String: ${numOfStr}`;
}


// Run the code
console.log(commaAndStringCounter(mainStr)); // Output: Commas: 3, String: 4

在这里你可以找到我的REPL

下面这个是最简单的逻辑,非常容易理解

  //Demo string with repeat char
let str = "Coffee"
//Splitted the str into an char array for looping
let strArr = str.split("")
//This below is the final object which holds the result
let obj = {};
//This loop will count char (You can also use traditional one for loop)
strArr.forEach((value,index)=>{
//If the char exists in the object it will simple increase its value
if(obj[value] != undefined)
{
obj[value] = parseInt(obj[value]) + 1;
}//else it will add the new one with initializing 1
else{
obj[value] =1;
}
});


console.log("Char with Count:",JSON.stringify(obj)); //Char with Count:{"C":1,"o":1,"f":2,"e":2}
let str = "aabgrhaab"
let charMap = {}


for(let char of text) {
if(charMap.hasOwnProperty(char)){
charMap[char]++
} else {
charMap[char] = 1
}
}

console.log(charMap);//{a: 4, b: 2, g: 1, r: 1, h: 1}

var mainStr = "str1,str2,str3,str4";
var splitStr = mainStr.split(",").length - 1; // subtracting 1 is important!
alert(splitStr);

拆分成一个数组给了我们一些元素,这些元素总是比字符的实例数多1。这可能不是内存效率最高的,但是如果你的输入总是很小,这是一种简单易懂的方法。

如果您需要解析非常大的字符串(大于几百个字符),或者这是在处理大量数据的核心循环中,我建议采用不同的策略。

有一个非常棘手的方法,但它是相反的:

const sampleStringText = "/john/dashboard/language";

假设上面的例子,为了计算正斜杠的数量,你可以这样做:

console.log( sampleStringText.split('/') - 1 );

所以我建议为它使用一个函数(TypeScript):

const counter = (sentence: string, char: string): number => sentence.split(char) - 1;
function len(text,char){


return text.innerText.split(string).length
}


console.log(len("str1,str2,str3,str4",","))

这是一个非常短的函数。

更新 06/10/2022

所以我运行了各种perf测试,如果您的用例允许,那么使用拆分似乎总体上表现最好。


function countChar(char: string, string: string): number  {


return string.split(char).length - 1


}


countChar('x', 'foo x bar x baz x')



我知道我来晚了,但我相当困惑没有人用最基本的方法回答这个问题。社区为这个问题提供的很大一部分答案是基于迭代的,但所有答案都是在每个字符的基础上移动字符串,这不是真正有效的。

当处理包含数千个字符的大字符串时,遍历每个字符以获取出现次数计数可能会变得相当无关,更不用说代码气味了。以下解决方案利用了sliceindexOf和受信任的传统while循环。这些方法避免了我们必须遍历每个字符,并将大大加快计算出现次数所需的时间。这些方法遵循的逻辑与需要字符串遍历的解析器和词法分析器中的相似。

使用Slice

在这种方法中,我们利用slice,并且在每个indexOf匹配中,我们将在字符串中移动并消除之前搜索的药水。每次我们调用indexOf时,它搜索的字符串的大小都会更小。

function countChar (char: string, search: string): number {
  

let num: number = 0;
let str: string = search;
let pos: number = str.indexOf(char);
  

while(pos > -1) {
str = str.slice(pos + 1);
pos = str.indexOf(char);
num++;
}


return num;


}


// Call the function
countChar('x', 'foo x bar x baz x') // 3


从位置使用IndexOf

与使用slice的第一种方法类似,但我们正在搜索的不是扩充字符串,它将利用indexOf方法中的from参数。

function countChar (char: string, str: string): number {
  

let num: number = 0;
let pos: number = str.indexOf(char);
  

while(pos > -1) {
pos = str.indexOf(char, pos + 1);
num++;
}


return num;


}


// Call the function
countChar('x', 'foo x bar x baz x') // 3


就个人而言,我选择第二种方法而不是第一种,但在处理大字符串时,两者都很好,性能也很好,但也有较小的字符串。

更新:这可能很简单,但不是最快的。请参阅下面的基准测试。


令人惊讶的是,13年来,这个答案还没有出现。直觉上,似乎应该是最快的:

const s = "The quick brown fox jumps over the lazy dog.";
const oCount = s.length - s.replaceAll('o', '').length;

如果字符串中只有两种字符,那么这仍然更快:


const s = "001101001";
const oneCount = s.replaceAll('0', '').length;

基准

const { performance } = require('node:perf_hooks');


const ITERATIONS = 10000000;
const TEST_STRING = "The quick brown fox jumps over the lazy dog.";


console.log(ITERATIONS, "iterations");


let sum = 0; // make sure compiler doesn't optimize code out
let start = performance.now();
for (let i = 0; i < ITERATIONS; ++i) {
sum += TEST_STRING.length - TEST_STRING.replaceAll('o', '').length;
}
let end = performance.now();
console.log("  replaceAll duration", end - start, `(sum ${sum})`);


sum = 0;
start = performance.now();
for (let i = 0; i < ITERATIONS; ++i) {
sum += TEST_STRING.split('o').length - 1
}
end = performance.now();
console.log("  split duration", end - start, `(sum ${sum})`);
10000 iterations
replaceAll duration 2.6167500019073486 (sum 40000)
split duration 2.0777920186519623 (sum 40000)
100000 iterations
replaceAll duration 17.563208997249603 (sum 400000)
split duration 8.087624996900558 (sum 400000)
1000000 iterations
replaceAll duration 128.71587499976158 (sum 4000000)
split duration 64.15841698646545 (sum 4000000)
10000000 iterations
replaceAll duration 1223.3415840268135 (sum 40000000)
split duration 629.1629169881344 (sum 40000000)

String.prototype.reduce = Array.prototype.reduce;


String.prototype.count = function(c) {
return this.reduce(((n, x) => n + (x === c ? 1 : 0)), 0)
};


const n = "bugs bunny was here".count("b")
console.log(n)

与上面的原型类似,但不为字符串分配数组。分配是上面几乎所有版本的问题,除了循环变体。这避免了循环代码,重用浏览器实现Array.reduce函数。