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.