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

问题描述 投票:491回答:41

我有字符串

a.b.c.d

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

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

java string
41个回答
679
投票

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

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

当它已经在commons lang时,为什么要自己写呢?

Spring Framework的一个内容是:

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

17
投票

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

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

好吧,有一个循环,但它是看不见的:-)

ーーー


14
投票

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

for(int i=0;i<s.length();num+=(s.charAt(i++)==delim?1:0))

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


13
投票

好的,受益于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是否会进行尾递归...如果不是,你会得到适当长串的同名堆栈溢出,当然。


11
投票

灵感来自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;
}

9
投票

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

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

9
投票

使用,你也可以使用流来实现这一目标。显然幕后有一个迭代,但你不必明确地写它!

public static long countOccurences(String s, char c){
    return s.chars().filter(ch -> ch == c).count();
}

countOccurences("a.b.c.d", '.'); //3
countOccurences("hello world", 'l'); //3

7
投票

完整样本:

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

7
投票

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

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

输出:

3

5
投票

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


5
投票

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

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

959
投票

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

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

4
投票
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

4
投票

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

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

3
投票

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

public static int count( final String s, final char c ) {
  final char[] chars = s.toCharArray();
  int count = 0;
  for(int i=0; i<chars.length; i++) {
    if (chars[i] == c) {
      count++;
    }
  }
  return count;
}

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


3
投票
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;
}

2
投票

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

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

2
投票

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

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

2
投票

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


2
投票

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

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

    }
}

2
投票
int count = (line.length() - line.replace("str", "").length())/"str".length();

2
投票

使用Eclipse Collections

int count = CharAdapter.adapt("a.b.c.d").count(c -> c == '.');

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

CharBag bag = CharAdapter.adapt("a.b.c.d").toBag();
int count = bag.occurrencesOf('.');

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


246
投票

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

   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)使用替换

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或a .... b ...... c ...... d ...等等它不起作用。它只是值得。人物之间只有一次

更多信息在github

Perfomance test(使用JMH,mode = AverageTime,得分0.0100.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

2
投票

好吧,有一个非常相似的任务我偶然发现了这个线程。我没有看到任何编程语言限制,因为groovy在java vm上运行:这是我如何使用Groovy解决我的问题。

"a.b.c.".count(".")

完成。


170
投票

迟早,某些东西必须循环。编写(非常简单)循环比使用像你需要的强大得多的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;
}

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


61
投票

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

String s = "a.b.c.d";
int charCount = s.replaceAll("[^.]", "").length();
println(charCount);

35
投票
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();

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

PhiLho's solution使用ReplaceAll(“[^。]”,“”),它不需要转义,因为[。]代表字符'dot',而不是'任何字符'。


27
投票

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

int count = "a.b.c.d".length() - "a.b.c.d".replace(".", "").length();

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


26
投票
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();

22
投票

一个较短的例子是

String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;
© www.soinside.com 2019 - 2024. All rights reserved.