How do I count the number of occurrences of a char in a String?

My 'idiomatic one-liner' for this is:

int count = StringUtils.countMatches("a.b.c.d", ".");

Why write it yourself when it's already in commons lang?

Spring Framework's oneliner for this is:

int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");

How about this. It doesn't use regexp underneath so should be faster than some of the other solutions and won't use a loop.

int count = line.length() - line.replace(".", "").length();

Summarize other answer and what I know all ways to do this using a one-liner:

   String testString = "a.b.c.d";

1) Using Apache Commons

int apache = StringUtils.countMatches(testString, ".");
System.out.println("apache = " + apache);

2) Using Spring Framework's

int spring = org.springframework.util.StringUtils.countOccurrencesOf(testString, ".");
System.out.println("spring = " + spring);

3) Using replace

int replace = testString.length() - testString.replace(".", "").length();
System.out.println("replace = " + replace);

4) Using replaceAll (case 1)

int replaceAll = testString.replaceAll("[^.]", "").length();
System.out.println("replaceAll = " + replaceAll);

5) Using replaceAll (case 2)

int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);

6) Using split

int split = testString.split("\\.",-1).length-1;
System.out.println("split = " + split);

7) Using Java8 (case 1)

long java8 = testString.chars().filter(ch -> ch =='.').count();
System.out.println("java8 = " + java8);

8) Using Java8 (case 2), may be better for unicode than case 1

long java8Case2 = testString.codePoints().filter(ch -> ch =='.').count();
System.out.println("java8 (second case) = " + java8Case2);

9) Using StringTokenizer

int stringTokenizer = new StringTokenizer(" " +testString + " ", ".").countTokens()-1;
System.out.println("stringTokenizer = " + stringTokenizer);

From comment: Be carefull for the StringTokenizer, for a.b.c.d it will work but for a...b.c....d or ...a.b.c.d or a....b......c.....d... or etc. it will not work. It just will count for . between characters just once

More info in github

Perfomance test (using JMH, mode = AverageTime, score 0.010 better then 0.351):

Benchmark              Mode  Cnt  Score    Error  Units
1. countMatches        avgt    5  0.010 ±  0.001  us/op
2. countOccurrencesOf  avgt    5  0.010 ±  0.001  us/op
3. stringTokenizer     avgt    5  0.028 ±  0.002  us/op
4. java8_1             avgt    5  0.077 ±  0.005  us/op
5. java8_2             avgt    5  0.078 ±  0.003  us/op
6. split               avgt    5  0.137 ±  0.009  us/op
7. replaceAll_2        avgt    5  0.302 ±  0.047  us/op
8. replace             avgt    5  0.303 ±  0.034  us/op
9. replaceAll_1        avgt    5  0.351 ±  0.045  us/op

Sooner or later, something has to loop. It's far simpler for you to write the (very simple) loop than to use something like split which is much more powerful than you need.

By all means encapsulate the loop in a separate method, e.g.

public static int countOccurrences(String haystack, char needle)
{
    int count = 0;
    for (int i=0; i < haystack.length(); i++)
    {
        if (haystack.charAt(i) == needle)
        {
             count++;
        }
    }
    return count;
}

Then you don't need have the loop in your main code - but the loop has to be there somewhere.

Tags:

Java

String