I need to count the number of occurrences of a character in a string.
For example, suppose my string contains:
var mainStr = "str1,str2,str3,str4";
I want to find the count of comma ,
character, which is 3. And the count of individual strings after the split along comma, which is 4.
I also need to validate that each of the strings i.e str1 or str2 or str3 or str4 should not exceed, say, 15 characters.
This question is related to
javascript
string
If you are using lodash, the _.countBy method will do this:
_.countBy("abcda")['a'] //2
This method also work with array:
_.countBy(['ab', 'cd', 'ab'])['ab'] //2
I was working on a small project that required a sub-string counter. Searching for the wrong phrases provided me with no results, however after writing my own implementation I have stumbled upon this question. Anyway, here is my way, it is probably slower than most here but might be helpful to someone:
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;
}
}
Please let me know if you find this implementation to fail or do not follow some standards! :)
UPDATE You may want to substitute:
for (var i = 0; i < input.length; i++) {
With:
for (var i = 0, input_length = input.length; i < input_length; i++) {
Interesting read discussing the above: http://www.erichynds.com/blog/javascript-length-property-is-a-stored-value
My solution with ramda js:
const testString = 'somestringtotest'
const countLetters = R.compose(
R.map(R.length),
R.groupBy(R.identity),
R.split('')
)
countLetters(testString)
You can also rest your string and work with it like an array of elements using
const mainStr = 'str1,str2,str3,str4';_x000D_
const commas = [...mainStr].filter(l => l === ',').length;_x000D_
_x000D_
console.log(commas);
_x000D_
Or
const mainStr = 'str1,str2,str3,str4';_x000D_
const commas = [...mainStr].reduce((a, c) => c === ',' ? ++a : a, 0);_x000D_
_x000D_
console.log(commas);
_x000D_
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);
In javascript you can use above code to get occurrence of a character in a string.
Performance of Split vs RegExp
var i = 0;_x000D_
_x000D_
var split_start = new Date().getTime();_x000D_
while (i < 30000) {_x000D_
"1234,453,123,324".split(",").length -1;_x000D_
i++;_x000D_
}_x000D_
var split_end = new Date().getTime();_x000D_
var split_time = split_end - split_start;_x000D_
_x000D_
_x000D_
i= 0;_x000D_
var reg_start = new Date().getTime();_x000D_
while (i < 30000) {_x000D_
("1234,453,123,324".match(/,/g) || []).length;_x000D_
i++;_x000D_
}_x000D_
var reg_end = new Date().getTime();_x000D_
var reg_time = reg_end - reg_start;_x000D_
_x000D_
alert ('Split Execution time: ' + split_time + "\n" + 'RegExp Execution time: ' + reg_time + "\n");
_x000D_
This below is the simplest logic, which is very easy to understand
//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}
Here is my solution. Lots of solution already posted before me. But I love to share my view here.
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
s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++
A quick Google search got this (from 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;
}
Use it like this:
test = 'one,two,three,four'
commas = test.count(',') // returns 3
I just did a very quick and dirty test on repl.it using Node v7.4. For a single character, the standard for loop is quickest:
Some code:
// 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');
}
Results from a few runs:
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
Update 2021-Feb-10: Fixed typo in repl.it demo
Update 2020-Oct-24: Still the case with Node.js 12 (play with it yourself here)
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}
I know this might be an old question but I have a simple solution for low-level beginners in JavaScript.
As a beginner, I could only understand some of the solutions to this question so I used two nested FOR loops to check each character against every other character in the string, incrementing a count variable for each character found that equals that character.
I created a new blank object where each property key is a character and the value is how many times each character appeared in the string(count).
Example function:-
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;
}
var mainStr = "str1,str2,str3,str4";
var splitStr = mainStr.split(",").length
alert(splitStr)
_x000D_
Add this function to sting prototype :
String.prototype.count=function(c) {
var result = 0, i = 0;
for(i;i<this.length;i++)if(this[i]==c)result++;
return result;
};
usage:
console.log("strings".count("s")); //2
I'm using Node.js v.6.0.0 and the fastest is the one with index (the 3rd method in Lo Sauer's answer).
The second is:
function count(s, c) {_x000D_
var n = 0;_x000D_
for (let x of s) {_x000D_
if (x == c)_x000D_
n++;_x000D_
}_x000D_
return n;_x000D_
}
_x000D_
Here's one just as fast as the split()
and the replace methods, which are a tiny bit faster than the regex method (in Chrome and Firefox both).
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;
}
}
Here is a similar solution, but it uses Array.prototype.reduce
function countCharacters(char, string) {
return string.split('').reduce((acc, ch) => ch === char ? acc + 1: acc, 0)
}
As was mentioned, String.prototype.split
works much faster than String.prototype.replace
.
The fastest method seems to be via the index operator:
function charOccurances (str, char)_x000D_
{_x000D_
for (var c = 0, i = 0, len = str.length; i < len; ++i)_x000D_
{_x000D_
if (str[i] == char)_x000D_
{_x000D_
++c;_x000D_
}_x000D_
}_x000D_
return c;_x000D_
}_x000D_
_x000D_
console.log( charOccurances('example/path/script.js', '/') ); // 2
_x000D_
Or as a prototype function:
String.prototype.charOccurances = function (char)_x000D_
{_x000D_
for (var c = 0, i = 0, len = this.length; i < len; ++i)_x000D_
{_x000D_
if (this[i] == char)_x000D_
{_x000D_
++c;_x000D_
}_x000D_
}_x000D_
return c;_x000D_
}_x000D_
_x000D_
console.log( 'example/path/script.js'.charOccurances('/') ); // 2
_x000D_
Easiest way i found out...
Example-
str = 'mississippi';
function find_occurences(str, char_to_count){
return str.split(char_to_count).length - 1;
}
find_occurences(str, 'i') //outputs 4
I made a slight improvement on the accepted answer, it allows to check with case-sensitive/case-insensitive matching, and is a method attached to the string object:
String.prototype.count = function(lit, cis) {
var m = this.toString().match(new RegExp(lit, ((cis) ? "gi" : "g")));
return (m != null) ? m.length : 0;
}
lit
is the string to search for ( such as 'ex' ), and cis is case-insensitivity, defaulted to false, it will allow for choice of case insensitive matches.
'I love StackOverflow.com'
for the lower-case letter 'o'
, you would use:
var amount_of_os = 'I love StackOverflow.com'.count('o');
amount_of_os
would be equal to 2
.
var amount_of_os = 'I love StackOverflow.com'.count('o', true);
This time, amount_of_os
would be equal to 3
, since the capital O
from the string gets included in the search.
The following uses a regular expression to test the length. testex ensures you don't have 16 or greater consecutive non-comma characters. If it passes the test, then it proceeds to split the string. counting the commas is as simple as counting the tokens minus one.
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.");
}
Simply, use the split to find out the number of occurrences of a character in a string.
mainStr.split(',').length
// gives 4 which is the number of strings after splitting using delimiter comma
mainStr.split(',').length - 1
// gives 3 which is the count of comma
ok, an other one with regexp - probably not fast, but short and better readable then others, in my case just '_'
to count
key.replace(/[^_]/g,'').length
just remove everything that does not look like your char but it does not look nice with a string as input
var i = 0;_x000D_
_x000D_
var split_start = new Date().getTime();_x000D_
while (i < 30000) {_x000D_
"1234,453,123,324".split(",").length -1;_x000D_
i++;_x000D_
}_x000D_
var split_end = new Date().getTime();_x000D_
var split_time = split_end - split_start;_x000D_
_x000D_
_x000D_
i= 0;_x000D_
var reg_start = new Date().getTime();_x000D_
while (i < 30000) {_x000D_
("1234,453,123,324".match(/,/g) || []).length;_x000D_
i++;_x000D_
}_x000D_
var reg_end = new Date().getTime();_x000D_
var reg_time = reg_end - reg_start;_x000D_
_x000D_
alert ('Split Execution time: ' + split_time + "\n" + 'RegExp Execution time: ' + reg_time + "\n");
_x000D_
My solution:
function countOcurrences(str, value){
var regExp = new RegExp(value, "gi");
return str.match(regExp) ? str.match(regExp).length : 0;
}
The fifth method in Leo Sauers answer fails, if the character is on the beginning of the string. e.g.
var needle ='A',
haystack = 'AbcAbcAbc';
haystack.split('').map( function(e,i){ if(e === needle) return i;} )
.filter(Boolean).length;
will give 2 instead of 3, because the filter funtion Boolean gives false for 0.
Other possible filter function:
haystack.split('').map(function (e, i) {
if (e === needle) return i;
}).filter(function (item) {
return !isNaN(item);
}).length;
What about string.split(desiredCharecter).length-1
Example:
var str = "hellow how is life"; var len = str.split("h").length-1; will give count 2 for character "h" in the above string;
And there is:
function character_count(string, char, ptr = 0, count = 0) {
while (ptr = string.indexOf(char, ptr) + 1) {count ++}
return count
}
Works with integers too!
I believe you will find the below solution to be very short, very fast, able to work with very long strings, able to support multiple character searches, error proof, and able to handle empty string searches.
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;
}
Example usage:
console.log(substring_count("Lorem ipsum dolar un sit amet.", "m "))_x000D_
_x000D_
function substring_count(source_str, search_str, index) {_x000D_
source_str += "", search_str += "";_x000D_
var count = -1, index_inc = Math.max(search_str.length, 1);_x000D_
index = (+index || 0) - index_inc;_x000D_
do {_x000D_
++count;_x000D_
index = source_str.indexOf(search_str, index + index_inc);_x000D_
} while (~index);_x000D_
return count;_x000D_
}
_x000D_
The above code fixes the major performance bug in Jakub Wawszczyk's that the code keeps on looks for a match even after indexOf says there is none and his version itself is not working because he forgot to give the function input parameters.
There are at least four ways. The best option, which should also be the fastest -owing to the native RegEx engine -, is placed at the top. jsperf.com is currently down, otherwise I would provide you with performance statistics.
Update: Please, find the performance tests here, and run them yourselves, so as to contribute your performance results. The specifics of the results will be given later.
("this is foo bar".match(/o/g)||[]).length
//>2
"this is foo bar".split("o").length-1
//>2
split not recommended. Resource hungry. Allocates new instances of 'Array' for each match. Don't try that for a >100MB file via FileReader. You can actually easily observe the EXACT resource usage using Chrome's profiler option.
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
searching for a single character
var stringsearch = "o"
,str = "this is foo bar";
for(var i=count=0; i<str.length; count+=+(stringsearch===str[i++]));
//>count:2
Update:
element mapping and filtering, not recommended due to its overall resource preallocation rather than using Pythonian 'generators'
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
Share: I made this gist, with currently 8 methods of character-counting, so we can directly pool and share our ideas - just for fun, and perhaps some interesting benchmarks :)
I have found that the best approach to search for a character in a very large string (that is 1 000 000 characters long, for example) is to use the replace()
method.
window.count_replace = function (str, schar) {
return str.length - str.replace(RegExp(schar), '').length;
};
You can see yet another JSPerf suite to test this method along with other methods of finding a character in a string.
The function takes string str as parameter and counts occurrence of each unique characters in the string. The result comes in key - value pair for each character.
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;
}
Source: Stackoverflow.com