最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Check how many times a char appears in a string - Stack Overflow

programmeradmin3浏览0评论

Simply trying to find how many times a given character appears in a string but I can't solve it any other way then this simple for-loop. Is there a method that would solve this quicker or more eloquently other than using Regex?

function countCharacter(str, char) {

  var count = 0;
  for(var i = 0; i < str.length; i++){
    if(str.charAt(i) === char)
      count++;
  }
 return count;
}

Simply trying to find how many times a given character appears in a string but I can't solve it any other way then this simple for-loop. Is there a method that would solve this quicker or more eloquently other than using Regex?

function countCharacter(str, char) {

  var count = 0;
  for(var i = 0; i < str.length; i++){
    if(str.charAt(i) === char)
      count++;
  }
 return count;
}
Share Improve this question asked Aug 10, 2017 at 2:12 ayeteoayeteo 2543 gold badges5 silver badges15 bronze badges 6
  • 4 the whole body of your function can be replaced with return str.split(char).length - 1; - bonus, you can search for occurrence of strings in string :p – Jaromanda X Commented Aug 10, 2017 at 2:13
  • 1 More eloquently - yes, there's always potential for abstraction. Quicker - no, you can't get around looking at every character of the string. – Bergi Commented Aug 10, 2017 at 2:24
  • You can change str.charAt(i) to str[i] to keep essentially the same algorithm with fewer function calls. "other than using Regex" - Why not regex? – nnnnnn Commented Aug 10, 2017 at 2:45
  • you can't be faster than O(n) here, because you have to turn every stone exactly once. I like to keep it simple like your code, I consider other fancy ways to be a show-off :D – TonyW Commented Aug 10, 2017 at 2:45
  • You can't get faster than O(n), but constants matter a lot, especially for JS where native code can be much faster than interpreted. See my answer for performance tests if speed is your main concern – Flight Odyssey Commented Aug 10, 2017 at 2:48
 |  Show 1 more ment

6 Answers 6

Reset to default 5

There are many possible ways are available in the market. I am adding a few of them.

Method 1:

str = "The man is as good as his word"
str.split('a')
output: (4) ["The m", "n is ", "s good ", "s his word"]
str.split('a').length - 1
output: 3

Method 2:

str = "The man is as good as his word"
str.split('').map( function(char,i)
    { if(char === 'a') 
        return i;
    } 
).filter(Boolean)
Output: (3) [5, 11, 19]

str.split('').map( function(char,i)
    { if(char === 'a') 
        return i;
    } 
).filter(Boolean).length

ouput: 3

Edit: As per ment we can also make use of filter().

    str.split('').filter(function(char, i){
        if(char == 'a'){
            return i;
        }
    })
    output: (3) ["a", "a", "a"]

str.split('').filter(function(char, i){
    if(char == 'a'){
        return i;
    }
}).length
output: 3

----edited by adding more cases from answers----

there are several ways, you can use split/for/regex/reduce/indexOf like this:

function countCharacter_reduce(str, ch) {
  return Array.prototype.reduce.call(str, (prev, cur) => cur === ch && ++prev && prev, 0);
}

function countCharacter_split(str, ch) {
  return str.split(ch).length - 1;
}

function countCharacter_for(str, ch) {
  for (var count = 0, ii = 0; ii < str.length; ii++) {
    if (str[ii] === ch)
      count++;
  }
  return count;
}

function countCharacter_regex(str, ch) {
  return str.length - str.replace(new RegExp(ch, 'g'), '').length;
}

function countCharacter_indexOf(str, char) {
  var start = 0;
  var count = 0;
  while ((start = str.indexOf(char, start) + 1) !== 0) {
    count++;
  }
  return count;
}

performance of them by running 1,000,000 times on counting '/' in a string.

-- case1: running 1000000 times on ( 'this/is/a/path/with/extension', '/' )
countCharacter_reduce: 2389.880ms
countCharacter_regex: 496.251ms
countCharacter_split: 114.709ms
countCharacter_for: 152.012ms
countCharacter_indexOf: 90.330ms

-- case2: running 1000000 times on ( '////////////', '/' )
countCharacter_reduce: 1138.051ms
countCharacter_regex: 619.886ms
countCharacter_split: 121.945ms
countCharacter_for: 74.542ms
countCharacter_indexOf: 204.242ms

Conclusion ('>' means 'has better performance'):

for|split|indexOf > regex > reduce.

furthermore, if the string contains more searching characters (like case2),

for>split>indexOf,

otherwise (like case1)

indexOf > split > for.

BTW: you can change the for indexOf method to fit multi-characters search (example is single character)

using reduce:

function countCharacter(str, char) {
    return str.split('').reduce((a, x) => x === char ? ++a : a, 0);
}

I guess this involves regex which you wanted to avoid but it's pretty quick:

function countCharacter(str, char) {
    return str.length - str.replace(new RegExp(char,"g"),"").length;
}

You can also try the str.split(char).length-1 approach suggested by Jaromanda.

Or, go all out with some fun recursion (pass 0 to startingFrom):

function countCharacter(str, char, startingFrom) {
    var idx = str.indexOf(char, startingFrom);
    return idx == -1 ? 0 : 1 + countCharacter(str, char, idx + 1);
}

You can get rid of the annoying extra argument at the cost of some efficiency:

function countCharacter(str, char) {
    var idx = str.indexOf(char);
    return idx == -1 ? 0 : 1 + countCharacter(str.substr(idx+1), char);
}

And here's a version optimized for speed (this is about 3 times faster on my browser than your original and much faster than the regex versions, according to jsperf):

function countCharacter(str, char) {
   var start = 0;
   var count = 0;
   while((start = str.indexOf(char, start)+1) !== 0) {
       count++;
   }
   return count;
}

Note that the indexOf approaches will generally be substantially faster than manually iterating through the string. See jsperf

Here you go. One line code

"hello".match(new RegExp('l','g')).length

replace 'l' with any char here, new RegExp('l','g').

that is

str.match(new RegExp(char,'g')).length

Have you thought of using the split() method? How about this -

function myFunction(str, char) {    
    return string.split(char).length - 1
}

Let me know what you think of this solution.

发布评论

评论列表(0)

  1. 暂无评论