我有一个字符串
(之前我曾表达过这个限制条件为“不使用循环”,以防你想知道为什么每个人都试图回答而不使用循环)。
a.b.c.d
我希望以惯用方式计算“.”的出现次数,最好是一行代码解决。(之前我曾表达过这个限制条件为“不使用循环”,以防你想知道为什么每个人都试图回答而不使用循环)。
a.b.c.d
我希望以惯用方式计算“.”的出现次数,最好是一行代码解决。这个怎么样?它没有使用正则表达式,因此应该比其他解决方案更快,并且不会使用循环。
int count = line.length() - line.replace(".", "").length();
我的“惯用一行代码”是:
int count = StringUtils.countMatches("a.b.c.d", ".");
如果已经有了 commons lang,为什么还要自己编写呢?
Spring Framework 的一行代码解决方案是:
int occurance = StringUtils.countOccurrencesOf("a.b.c.d", ".");
总结其他答案和我所知道的所有方法,用一行代码实现以下操作:
String testString = "a.b.c.d";
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) 使用 replace
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(第二种情况)
int replaceAllCase2 = testString.length() - testString.replaceAll("\\.", "").length();
System.out.println("replaceAll (second case) = " + replaceAllCase2);
6) 使用split
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)可能比情况1更适合Unicode。
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);
来自评论:要小心StringTokenizer,对于a.b.c.d,它可以工作,但对于a...b.c....d或...a.b.c.d或a....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
"123 has 2".codePoints().filter((c) -> c == "".codePointAt(0)).count()
- Tom BlodgetStringUtils.countMatches
循环遍历索引并使用charAt
; Spring Framework的StringUtils.countOccurencesOf
重复使用indexOf
。OpenJDK的String.indexOf
基本上在循环中使用charAt
。 - Solomon Ucko迟早会有 某些东西 需要循环。你更容易编写(非常简单的)循环,而不是使用像 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 = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();
ReplaceAll(".") 将替换所有字符。
PhiLho's solution 使用 ReplaceAll("[^.]",""),无需转义,因为 [.] 表示字符 'dot',而不是 '任何字符'。
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();
我的“惯用单行代码”解决方案:
int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();
不知道为什么使用StringUtils的解决方案被接受了。
String text = "a.b.c.d";
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("a.b.c.d",'.',0));
好的,有一个循环,但它是隐形的 :-)
-- Yonatan