如何计算字符串中char的出现次数?

我有字符串

abcd 

我想计算’。’的出现次数。 以惯用的方式,最好是单线。

(之前我曾把这种约束表达为“没有循环”,如果你想知道为什么每个人都试图回答而不使用循环)。

我的’惯用单线’是这样的:

 int count = StringUtils.countMatches("abcd", "."); 

当它已经在公共场所时,为什么要自己写呢?

Spring Framework的oneliner就是:

 int occurance = StringUtils.countOccurrencesOf("abcd", "."); 

这个怎么样。 它不使用下面的regexp,因此应该比其他一些解决方案更快,并且不会使用循环。

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

总结其他答案以及我所知道的使用单线程的所有方法:

  String testString = "abcd"; 

1)使用Apache Commons

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

2)使用Spring Framework

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

3)使用替换

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

4)使用replaceAll (案例1)

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

5)使用replaceAll (案例2)

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

6)使用拆分

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

7)使用Java8 (案例1)

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

8)使用Java8 (案例2),unicode可能比案例1更好

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

9)使用StringTokenizer

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

来自评论 :小心对于StringTokenizer,对于abcd它会起作用但是…… bc … d或…… abcd或者…… b …… c …… d …等等它不起作用。 它只是值得。 字符之间只有一次

更多信息在github中

性能测试 (使用JMH ,模式= AverageTime,得分0.010优于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 

迟早, 某些东西必须循环。 编写(非常简单的)循环比使用像你需要的function强大得多的split要简单得多。

通过所有方式将循环封装在单独的方法中,例如

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

然后你不需要在主代码中使用循环 - 但循环必须在某处。

我有一个类似于Mladen的想法,但相反……

 String s = "abcd"; int charCount = s.replaceAll("[^.]", "").length(); println(charCount); 
 String s = "abcd"; int charCount = s.length() - s.replaceAll("\\.", "").length(); 

ReplaceAll(“。”)将替换所有字符。

PhiLho的解决方案使用ReplaceAll(“[^。]”,“”),它不需要转义,因为[。]代表字符’dot’,而不是’任何字符’。

我的’惯用单线’解决方案:

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

不知道为什么接受使用StringUtils的解决方案。

 String s = "abcd"; long result = s.chars().filter(ch -> ch == '.').count(); 

一个较短的例子是

 String text = "abcd"; int count = text.split("\\.",-1).length-1; 

这是一个没有循环的解决方案:

 public static int countOccurrences(String haystack, char needle, int i){ return ((i=haystack.indexOf(needle, i)) == -1)?0:1+countOccurrences(haystack, needle, i+1);} System.out.println("num of dots is "+countOccurrences("abcd",'.',0)); 

好吧,有一个循环,但它是看不见的 🙂

– Yonatan

我不喜欢为此目的分配新字符串的想法。 由于字符串后面已经有一个char数组,它存储了它的值,因此String.charAt()实际上是免费的。

 for(int i=0;i 

如果没有需要收集的额外分配,只需要1行或更少,只需要J2SE。

好的,受到Yonatan解决方案的启发,这里有一个纯粹递归的方法 – 使用的唯一库方法是length()charAt() ,它们都没有做任何循环:

 public static int countOccurrences(String haystack, char needle) { return countOccurrences(haystack, needle, 0); } private static int countOccurrences(String haystack, char needle, int index) { if (index >= haystack.length()) { return 0; } int contribution = haystack.charAt(index) == needle ? 1 : 0; return contribution + countOccurrences(haystack, needle, index+1); } 

递归计数是否为循环取决于您使用的确切定义,但它可能会尽可能接近您。

我不知道这些天大多数JVM是否会进行尾递归…如果不是,你当然会得到适当长串的同名堆栈溢出。

灵感来自Jon Skeet,一个不会让你的筹码无法破坏的非循环版本。 如果要使用fork-join框架,也是有用的起点。

 public static int countOccurrences(CharSequeunce haystack, char needle) { return countOccurrences(haystack, needle, 0, haystack.length); } // Alternatively String.substring/subsequence use to be relatively efficient // on most Java library implementations, but isn't any more [2013]. private static int countOccurrences( CharSequence haystack, char needle, int start, int end ) { if (start == end) { return 0; } else if (start+1 == end) { return haystack.charAt(start) == needle ? 1 : 0; } else { int mid = (end+start)>>>1; // Watch for integer overflow... return countOccurrences(haystack, needle, start, mid) + countOccurrences(haystack, needle, mid, end); } } 

(免责声明:未经测试,未编译,不合理。)

也许最好的(单线程,没有代理对支持)方式来编写它:

 public static int countOccurrences(String haystack, char needle) { int count = 0; for (char c : haystack.toCharArray()) { if (c == needle) { ++count; } } return count; } 

不确定这个的效率,但它是我可以编写的最短代码而不引入第三方库:

 public static int numberOf(String target, String content) { return (content.split(target).length - 1); } 

使用java-8,您还可以使用流来实现此目的。 显然幕后有一个迭代,但你不必明确地写它!

 public static long countOccurences(String s, char c){ return s.chars().filter(ch -> ch == c).count(); } countOccurences("abcd", '.'); //3 countOccurences("hello world", 'l'); //3 

完整样本:

 public class CharacterCounter { public static int countOccurrences(String find, String string) { int count = 0; int indexOf = 0; while (indexOf > -1) { indexOf = string.indexOf(find, indexOf + 1); if (indexOf > -1) count++; } return count; } } 

呼叫:

 int occurrences = CharacterCounter.countOccurrences("l", "Hello World."); System.out.println(occurrences); // 3 

获得答案的最简单方法如下:

 public static void main(String[] args) { String string = "abcd"; String []splitArray = string.split("\\."); System.out.println("No of . chars is : " + splitArray.length-1); } 

如果您使用的是Spring框架,也可以使用“StringUtils”类。 该方法将是“countOccurrencesOf”。

也可以在Java 8中使用reduce来解决这个问题:

 int res = "abdsd3$asda$asasdd$sadas".chars().reduce(0, (a, c) -> a + (c == '$' ? 1 : 0)); System.out.println(res); 

输出:

 3 
 import java.util.Scanner; class apples { public static void main(String args[]) { Scanner bucky = new Scanner(System.in); String hello = bucky.nextLine(); int charCount = hello.length() - hello.replaceAll("e", "").length(); System.out.println(charCount); } }// COUNTS NUMBER OF "e" CHAR´s within any string input 

您可以在一行代码中使用split()函数

 int noOccurence=string.split("#").length-1; 

虽然方法可以隐藏它,但没有循环(或递归)就无法计数。 出于性能原因,您希望使用char []。

 public static int count( final String s, final char c ) { final char[] chars = s.toCharArray(); int count = 0; for(int i=0; i 

使用replaceAll(即RE)听起来不是最好的方法。

 public static int countOccurrences(String container, String content){ int lastIndex, currIndex = 0, occurrences = 0; while(true) { lastIndex = container.indexOf(content, currIndex); if(lastIndex == -1) { break; } currIndex = lastIndex + content.length(); occurrences++; } return occurrences; } 
 String[] parts = text.split("."); int occurances = parts.length - 1; " It's a great day at OSG Dallas! " -- Famous Last Words 

好吧,这是了解Java的一个案例,尤其是您对Java中已有的集合类的基本理解。 如果你看看这里的整篇文章,那么斯蒂芬霍金对宇宙起源的解释,达尔文关于进化的平装本以及基因罗登伯里的星际迷航演员选择,以及他们为何与威廉·夏特纳一起探讨如何做这快速而轻松……

……我还需要说吗?

在代码中的某个地方,必须循环。 解决这个问题的唯一方法是完全展开循环:

 int numDots = 0; if (s.charAt(0) == '.') { numDots++; } if (s.charAt(1) == '.') { numDots++; } if (s.charAt(2) == '.') { numDots++; } 

…等等,但是你是那个在源编辑器中手动完成循环的人 – 而不是运行它的计算机。 看到伪代码:

 create a project position = 0 while (not end of string) { write check for character at position "position" (see above) } write code to output variable "numDots" compile program hand in homework do not think of the loop that your "if"s may have been optimized and compiled to 

这是一个略有不同的样式递归解决方案:

 public static int countOccurrences(String haystack, char needle) { return countOccurrences(haystack, needle, 0); } private static int countOccurrences(String haystack, char needle, int accumulator) { if (haystack.length() == 0) return accumulator; return countOccurrences(haystack.substring(1), needle, haystack.charAt(0) == needle ? accumulator + 1 : accumulator); } 

为什么不拆分字符然后获得结果数组的长度。 数组长度总是实例数+ 1.对吗?

以下源代码将为您提供由用户输入的单词中出现的给定字符串数量: –

 import java.util.Scanner; public class CountingOccurences { public static void main(String[] args) { Scanner inp= new Scanner(System.in); String str; char ch; int count=0; System.out.println("Enter the string:"); str=inp.nextLine(); while(str.length()>0) { ch=str.charAt(0); int i=0; while(str.charAt(i)==ch) { count =count+i; i++; } str.substring(count); System.out.println(ch); System.out.println(count); } } } 
 int count = (line.length() - line.replace("str", "").length())/"str".length(); 

使用Eclipse集合

 int count = CharAdapter.adapt("abcd").count(c -> c == '.'); 

如果要计算多个字符,可以使用CharBag ,如下所示:

 CharBag bag = CharAdapter.adapt("abcd").toBag(); int count = bag.occurrencesOf('.'); 

注意:我是Eclipse Collections的提交者。