778

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Based on the top rated answer below, you can also use this online tool to cross check the results: https://magictools.dev/#!/tools/character-occurences – WJA Jan 02 '22 at 22:05

39 Answers39

1071

I have updated this answer. I like the idea of using a match better, but it is slower:

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

Use a regular expression literal if you know what you are searching for beforehand, if not you can use the RegExp constructor, and pass in the g flag as an argument.

match returns null with no results thus the || []

The original answer I made in 2009 is below. It creates an array unnecessarily, but using a split is faster (as of September 2014). I'm ambivalent, if I really needed the speed there would be no question that I would use a split, but I would prefer to use match.

Old answer (from 2009):

If you're looking for the commas:

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

If you're looking for the str

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

Both in @Lo's answer and in my own silly performance test split comes ahead in speed, at least in Chrome, but again creating the extra array just doesn't seem sane.

Corey
  • 6,612
  • 4
  • 20
  • 28
Bjorn
  • 69,215
  • 39
  • 136
  • 164
  • 11
    test shows Firefox is a lot faster than any other browser when splitting. http://jsperf.com/count-the-number-of-occurances-in-string – vsync Jun 14 '11 at 11:59
  • Chrome 33 at least on Windows 7 x64 beats Firefox 27 in splitting but not regular expression. 2/25/2014 – Rob R. Feb 25 '14 at 14:52
  • 1
    This is gonna be way slower than regex – B T Sep 02 '14 at 19:57
  • 4
    Uh, I just tested vsync's jsperf and the regex was *slower* in Chrome, Firefox and IE. 68%, 100%, and 14% respectively. I have an i7 2600. – Moss Sep 05 '14 at 18:56
  • 1
    You are correct @Moss, I created this jsperf http://jsperf.com/performance-of-match-vs-split and split is much, much faster, I still think the regexp is the better answer, but it isn't faster. – Bjorn Sep 08 '14 at 18:16
  • 99
    I really dislike the idea of using a regex because "you like it better". Regexes have their purpose, but generally when there's a simple non-regex solution it's a better choice. Also note that both methods create an array, so that's not a reason to use a regex either. – Jasper Sep 09 '14 at 09:34
  • 8
    I like it better *in this case* for a reason. Splitting a string into an array to get a number of occurrences is a round about way to get that information. Splitting an array is only faster because of implementation details, something that can change, whereas getting the number of matches is an improvement in readability, the intent is obvious and doesn't create and fill an unused data structure. – Bjorn Sep 10 '14 at 17:18
  • 1
    The separater character may be any character, including meta character in regular expression. Try `Console.log(("str1,str2,str3,str4".match(/./g) || []).length);` which returns unexpected result. – Gqqnbig Oct 16 '15 at 23:29
  • 47
    split() is a basic tool in javascript, conceptually simple, and counting the splits gives clear intention and is totally readable. – bradw2k Dec 03 '15 at 21:10
  • 1
    bradw2k when you split your intention is to keep the parts around the separator. In this case you are throwing them away, and taking advantage of the fact that there will be one more 'part' than 'separator'. However you need a -1 to convert from one concept to another. The regex matches x times where x is the number of separators. So no. – Gerard ONeill Apr 12 '17 at 18:44
  • 2
    bjorn -- unfortunately a regex is more than a 'match' -- it returns results, in an array, With a global search you have an array of results. So from a 'creating an array doesn't seem sane' standpoint, the split is probably better. – Gerard ONeill Apr 12 '17 at 18:47
  • I used `console.log(("^str1^str2^str3^str4".match(/^/g) || []).length); ` it logs: 1. What am I missing here? – Abrar Dec 17 '18 at 10:59
  • 2
    @Abrar `^` has special meaning in a regex. Use `/\^/g` instead, to match a literal `^` character. – jpaugh Jan 10 '19 at 22:49
  • 3
    So you're saying the "new" version is 50% longer, and slower to run? I'll stick with the *"old way",* thanks! – ashleedawg Dec 22 '20 at 13:21
  • Very good! I like the regex solution, however, as a slight modification instead of using the || operator in case the left hand side with the match returns null instead of an empty array, I would recommend using the nullish coalescing operator, or ?? which more explicitly returns left unless it is null/undefined! – Kevin L Xu Mar 19 '23 at 14:49
  • For current browsers the performance of regex is much higher, with Firefox 114 I get about 40% faster regex vs the split version. – laserbeamer Jul 05 '23 at 20:26
293

There are at least five ways. The best option, which should also be the fastest (owing to the native RegEx engine) is placed at the top.

Method 1

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

Method 2

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

Split not recommended as it is resource hungry. It allocates new instances of 'Array' for each match. Don't try it for a >100MB file via FileReader. You can observe the exact resource usage using Chrome's profiler option.

Method 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

Method 4

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++]));
     // returns 2

Method 5

Element mapping and filtering. This is 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
    // returns 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 :)

user229044
  • 232,980
  • 40
  • 330
  • 338
Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
  • 34
    It took me a little while to realize what `||[]` was doing but this answer is great! For anyone else scratching their heads, `match()` returns `null` if no matches are found and `||[]` will return a 0 length array if the `match()` returns `null`, meaning `length()` will return 0 instead of producing a type error. – Nathan Sep 20 '12 at 06:27
  • 1
    Nathan, to my defense, I did elaborate on that prior to writing the code above: https://gist.github.com/2757164 . I want to avoid blog-posts of small code-pieces, which however would have allowed you instant access through google-search. Gist as a snippet repository is very sparsely indexed and less than ideal. PS: I too hate unclear syntactic idiosyncrasies. – Lorenz Lo Sauer Sep 20 '12 at 15:39
  • 2
    Lo Sauer, no need to defend yourself, the code is solid and I learned something on my own by figuring out how it worked :) I prefer this method over what is actually marked as the answer. There should be no need to split a string if we're not going to use the results. – Nathan Sep 20 '12 at 23:52
  • 3
    Your third method (also, unfortunately, the fastest), will miss any match at index 0 in the haystack. You could fix it by using a do...while loop instead: var strsearch = "o", str = "othis is foo bar", index = -1, count = -1; do { index = str.indexOf(strsearch, index+1); count++; } while (index != -1); count – Augustus Nov 24 '13 at 16:28
  • 1
    It suffices to set the start `index = -2`, but thanks a lot @Augustus – Lorenz Lo Sauer Nov 24 '13 at 20:10
  • @Augustus How did you arrive at the conclusion that the third method is the fastest? [jsperf results](http://jsperf.com/char-count-methods) seem to suggest the second method (`split`) is the fastest. – Majid Fouladpour Jan 27 '14 at 07:10
  • 1
    I just added another test case, without all the special auto string to int conversions (the +(string === str[i++])) and it's by far the fastest: http://jsperf.com/count-the-number-of-characters-in-a-string/15 – PiniH Apr 07 '15 at 10:02
  • @LoSauer I don't see how #4 couldn't be the fastest. How can you beat a simple JS loop as a Regex expression that has to spin up the intermediate structure and then do its own loop. – Slight May 05 '16 at 19:33
  • WHY in the Earth you `map` and then `filter(Boolean)` rather than just `filter` by the character in #5? – Andre Figueiredo Oct 28 '18 at 16:55
  • To get #4 to work in my crazy DGLogik dglux_server JavaScript-like environment, I had to use charAt instead of array indexing with [] (square brackets). Surprisingly, jsperf.com says charAt is faster than array indexing. – buzz3791 Jul 16 '19 at 18:58
26

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
Philippe Boissonneault
  • 3,949
  • 3
  • 26
  • 33
  • what about `"stringsstringstrings".count("str")` ? – Toskan Apr 17 '20 at 22:39
  • 2
    @Toskan Please look at OPs question, which is about "a character". I guess that is why the parameter is called "c" and not "s" - for "[c]haracter", not "[s]tring". Most of the other answers are HORRIBLE, people throw around arrays and extra objects for this extremely simple task as if memory allocation is free. – Mörre Mar 02 '22 at 19:25
26

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

angabriel
  • 4,979
  • 2
  • 35
  • 37
Pranjal Successena
  • 907
  • 1
  • 11
  • 24
14

You can also rest your string and work with it like an array of elements using

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

console.log(commas);

Or

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

console.log(commas);
Yosvel Quintero
  • 18,669
  • 5
  • 37
  • 46
  • Is this an attempt to solve a simple problem with as much (actual) effort as possible? – Mörre Mar 02 '22 at 19:30
  • 1
    I mean, it's the more sensible option. I don't know about performance, but it's a lot easier to understand "go filter this string's letters and count how many are left" than to understand "split this string every time you see this letter, then count how many there are, and subtract one." – DexieTheSheep May 23 '22 at 18:22
14

UPDATE: This might be simple, but it is not the fastest. See benchmarks below.


It's amazing that in 13 years, this answer hasn't shown up. Intuitively, it seems like it should be fastest:

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

If there are only two kinds of character in the string, then this is faster still:


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

BENCHMARKS

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)
Joe Lapp
  • 2,435
  • 3
  • 30
  • 42
  • Simple and elegant solution. – Alok Ranjan Sep 13 '22 at 13:57
  • 1
    This is not the fastest method and actually performs the slowest comparatively against most answers to this question. Sure, it is a great one liner but it is not the fastest in terms of performance and it if you are working with a large string it likely the slowest. The fastest is actually using `string.split('o').length - 1` – User_coder Oct 06 '22 at 21:57
  • @User_coder, thanks for catching me not doing my homework. – Joe Lapp Oct 11 '22 at 02:03
14

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
user253751
  • 57,427
  • 7
  • 48
  • 90
10

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.

Vencovsky
  • 28,550
  • 17
  • 109
  • 176
uladzimir
  • 5,639
  • 6
  • 31
  • 50
9

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
Geng Jiawen
  • 8,904
  • 3
  • 48
  • 37
7

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

halfbit
  • 3,773
  • 2
  • 34
  • 47
6

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.

Valera Rozuvan
  • 181
  • 2
  • 6
  • It is obvious that that if your code somehow iterates over a million characters 500000 times a second, my CPU is running at at least 100GHz (assuming no SIMD; even then it would be at least 40GHz). Thus I do not believe that this benchmark is correct. – the default. Jun 09 '20 at 15:11
5

Performance of 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");
Clive Paterson
  • 1,663
  • 1
  • 15
  • 10
5

UPDATE 06/10/2022

So I ran various perf tests and if your use case allows it, it seems that using split is going to perform the best overall.


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

  return string.split(char).length - 1

}

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


I know I am late to the party here but I was rather baffled no one answered this with the most basic of approaches. A large portion of the answers provided by the community for this question are iteration based but all are moving over strings on a per-character basis which is not really efficient.

When dealing with a large string that contains thousands of characters walking over each character to get the occurance count can become rather extraneous not to mention a code-smell. The below solutions take advantage of slice, indexOf and the trusted traditional while loop. These approaches prevent us having to walk over each character and will greatly speed up the time it takes to count occurances. These follow similar logic to that you'd find in parsers and lexical analyzers that require string walks.

Using with Slice

In this approach we are leveraging slice and with every indexOf match we will move our way through the string and eliminate the previous searched potions. Each time we call indexOf the size of the string it searches will be smaller.

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

Using with IndexOf from position

Similar to the first approach using slice but instead of augmenting the string we are searching it will leverage the from parameter in indexOf method.

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

Personally, I go for the second approach over the first, but both are fine and performant when dealing with large strings but also smaller sized ones too.

User_coder
  • 477
  • 1
  • 7
  • 21
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.


To search the string '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.


If we were to search the same string again using case-insensitive matching, you would use:
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.

Dendromaniac
  • 378
  • 1
  • 14
4

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
4

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)

NuSkooler
  • 5,391
  • 1
  • 34
  • 58
  • Nice work @NuSkooler! A few caviats: Try it with longer strings, (like looking for '\n'-s a pop song), and try and run all the counts on different s. Say `charCountN(s+i, c)`. Also, you have a typo: charCount3 is mistyped as charCount2, therefore the similar results. If you try it with my modifications, you'll find that split is the winner with regex match coming in as second. – Barney Szabolcs Feb 08 '21 at 21:50
  • 1
    Thanks @BarneySzabolcs! Updated the repl demo and re-ran the results. I did leave the strings the same -- as you say, YMMV. I'm sure some other tricks that work in lower level languages could also work here especially for longer strings. – NuSkooler Feb 10 '21 at 21:55
4

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

Here you find my REPL

Md. Jamal Uddin
  • 754
  • 8
  • 17
3
s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++
wlf
  • 851
  • 1
  • 9
  • 15
3

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

http://jsfiddle.net/5ZzHt/1/

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

Jakub Wawszczyk
  • 377
  • 3
  • 11
  • 1
    Yes, and it would work for substring, not only subchars. However, you need to add the parameters to the function :) – Nico Mar 11 '16 at 13:12
2

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;

2

The fastest method seems to be via the index operator:

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

Or as a prototype function:

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
zoran404
  • 1,682
  • 2
  • 20
  • 37
2
function len(text,char){

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

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

This is a very short function.

DerpyCoder
  • 127
  • 1
  • 6
2

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)

Similar to the prototype based above, but does not allocate an array for the string. Allocation is the problem of nearly every version above, except the loop variants. This avoids loop code, reusing the browser implemented Array.reduce function.

citykid
  • 9,916
  • 10
  • 55
  • 91
1

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) {
  var n = 0;
  for (let x of s) {
    if (x == c)
      n++;
  }
  return n;
}
Marc K.
  • 69
  • 1
  • 7
1

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;
  }
}
Andrew
  • 5,839
  • 1
  • 51
  • 72
Gerard ONeill
  • 3,914
  • 39
  • 25
  • **Wow!** This turns out to be like 10X slower than the `split().length - 1` approach for me in FF! This makes me mad! – Andrew Jun 14 '20 at 06:43
  • Haha. I hate needing a performance optimization - but 10x means you need it! The FF JIT must be horrible. Too bad its my preferred browser... Hang in there - you never know what gets optimized and what doesn't. – Gerard ONeill Jun 15 '20 at 18:34
  • Well it's probably just that `split()` is implemented at a lower level whereas storing and accessing characters of a string is at high level JS. I wonder what might prevent JITing your code... Hmm... – Andrew Jun 15 '20 at 23:53
  • Yay! I figured it out! It doesn't like your `for` loop. I'll update your answer; with the regular `for` loop, it's just as fast as `split()`. I believe the reasons why are the same as listed here: https://stackoverflow.com/a/43821929/1599699 – Andrew Jun 15 '20 at 23:58
  • 1
    Andrew - you aren't supposed to *change* the answer, just comment on it. My original post provided an alternative that was optimized (at the time) in chrome, but not firefox. It was a different form that perhaps someone might have a use for. Your version matches other answers here making my answer hidden and useless. I'm glad you got your algorithm set. However, I'm not invested in Javascript enough to change my answer. This note is a historical comment for others. Check the edits for the original version. – Gerard ONeill Jun 22 '20 at 19:40
  • I understand your reasoning, but consider that: 1. Most of the others are still not like yours, and for those that are: 2. I did not change the substance of your answer, only the type of for loop and efficiency of it (it's still doing the same thing, just much faster), 3. Firefox is a major web browser, so even if someone is developing on Chrome there's a good chance that they care about the performance still, especially for this task, and especially because: 4. My change increases the speed by a factor of about 10. – Andrew Jun 23 '20 at 20:11
  • However, perhaps what should have been done and still could be done is to leave the original answer in the answer but suggest my changes for those that care about a 10X performance increase on FF. Sorry, I did not mean to step on your toes. – Andrew Jun 23 '20 at 20:12
1

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!

1

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

Splitting into an array gives us a number of elements, which will always be 1 more than the number of instances of the character. This may not be the most memory efficient, but if your input is always going to be small, this is a straight-forward and easy to understand way to do it.

If you need to parse very large strings (greater than a few hundred characters), or if this is in a core loop that processes large volumes of data, I would recommend a different strategy.

Tyler Forsythe
  • 1,471
  • 17
  • 22
  • While this code may provide a solution to the question, it's better to add context as to why/how it works. This can help future users learn and eventually apply that knowledge to their own code. You are also likely to have positive-feedback/upvotes from users, when the code is explained. – Amit Verma Feb 06 '21 at 18:32
1

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.");
}
Jonathan Fingland
  • 56,385
  • 11
  • 85
  • 79
0

My solution:

function countOcurrences(str, value){
   var regExp = new RegExp(value, "gi");
   return str.match(regExp) ? str.match(regExp).length : 0;  
}
Gere
  • 2,114
  • 24
  • 24
  • This will not work as `String.prototype.match` returns `null` without matches. That means no reference to an object with a `length` attribute. In other words: `String.prototype.match.call('willnotwork', /yesitwill/) === null` – Lorenz Lo Sauer Sep 03 '13 at 21:38
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;

one more answer:

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

console.log(count("abfsdfsddsfdfdsfdsfdsfda"))
phuwin
  • 3,130
  • 4
  • 26
  • 49
0

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

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 "))

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

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.

Jack G
  • 4,553
  • 2
  • 41
  • 50
0
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.

Nitin .
  • 808
  • 9
  • 12
0

My solution with ramda js:

const testString = 'somestringtotest'

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

countLetters(testString)

Link to REPL.

Michal
  • 4,952
  • 8
  • 30
  • 63
0

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;

} 
  • You forgot the second part of the question: "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." – Maxime Launois Jun 09 '19 at 15:17
0
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}

Pradeepta
  • 268
  • 2
  • 3
0

There is a very tricky way, but it is in reverse:

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

Assume the above sample, for counting the number of forward-slashs you can do like this:

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

So I recommended to use a function for it (TypeScript):

const counter = (sentence: string, char: string): number => sentence.split(char) - 1;
AmerllicA
  • 29,059
  • 15
  • 130
  • 154
-1

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");
webdev
  • 47
  • 6
-1

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}