当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何计算字符串中char的出现次数?》经验,为你挑选了20个好方法。

我有字符串

a.b.c.d

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

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



1> Andreas Wede..:

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

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


最简单的方法.聪明一点.它适用于Android,没有StringUtils类
这是最好的答案.它是最好的原因是因为您不必导入另一个库.
可以通过在自己的"StringUtils"类中创建一个方法来最小化丑陋的代码.然后丑陋的代码恰好在一个地方,其他地方都很可读.
循环方法比这快_much_.特别是当想要计算char而不是String时(因为没有String.replace(char,char)方法).在15个字符的字符串上,我得到的差异为6049 ns vs 26,739 ns(平均超过100runs).原始数字是巨大的差异,但明智的是......它加起来.避免内存分配 - 使用循环!
非常实用,但很丑陋.我不推荐它,因为它会导致令人困惑的代码.
只想为新手添加一件东西.如果某人的字符串长于".",则在该情况下将计数除以字符串的长度以获得该子字符串的正确计数.
String.replace(CharSequnce,CharSequence)确实使用regexp(查看此OpenJDK源代码:http://goo.gl/O9dQzg)对于1个字符到1个字符的替换,使用String.replace(char,char)以获得更好的性能.它只是迭代String的字符:http://goo.gl/2FbcWP
它不一定比其他解决方案更快,比如`StringUtils.countMatches`,因为它必须为返回的String分配一些内存.当性能不重要时仍然是一个很好的解决方案.
这必须通过字符串*三次*次; 首先它必须计算长度,然后它必须替换要计数的字符(这也涉及创建一个新的字符串),然后它必须再次计算长度.我想知道一个循环有多糟糕(显然这不是Andreas的问题,而是OP的问题)
@Grodriguez错了,Java的`String`不是以null结尾的,并且不必遍历字符来确定它的长度.相反,它在内部使用一个字符数组.`Array.length`是O(1).
另一个有趣的变体可以计算整个字符串或字符的出现:`int count =(sourceString.length() - sourceString.replace(searchString,"").length())/ searcString.length();`

2> Cowan..:

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

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

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

Spring Framework的oneliner就是:

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


[Guava](https://code.google.com/p/guava-libraries/)等效:`int count = CharMatcher.is('.').countIn("abcd");`... As [已回答by dogbane](http://stackoverflow.com/a/3764170/56285)重复的问题.
虽然我不会这样做,但它是(a)要求第三方库和(b)昂贵.
在我工作过的每家公司,价格昂贵的是,有很多写得不好且维护不善的"*Utils"课程.您的部分工作是了解Apache Commons中的可用内容.

3> Viacheslav V..:

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

   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中

性能测试(使用JMH,模式=平均时间,得分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



4> Jon Skeet..:

迟早,某些东西必须循环.编写(非常简单)循环比使用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;
}

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


(我甚至不确定评论的"堆栈"位来自哪里.它不像*这个*答案是我的递归,这对堆栈来说确实很讨厌.)
for(int i = 0,l = haystack.length(); i @sulai:面对一个*琐碎的*JIT优化,克里斯关注的是毫无根据的IMO.三年之后,是否有任何理由引起你的注意?只是感兴趣.
不仅如此,这可能是一个反优化,而不考虑jit的作用.例如,如果您在数组for循环中执行上述操作,则可能会使事情变得更糟.

5> PhiLho..:

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

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


我不认为使用正则表达式并为计数创建一个新字符串是个好主意.我只想创建一个静态方法,循环字符串中的每个字符来计算数字.

6> Mladen Prajd..:
String s = "a.b.c.d";
int charCount = s.length() - s.replaceAll("\\.", "").length();

ReplaceAll(".")将替换所有字符.

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



7> mlchen850622..:

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

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

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


因为这种解决方案效率很低
在这篇文章中有一个与此类似的旧解决方案.

8> fubo..:
String s = "a.b.c.d";
long result = s.chars().filter(ch -> ch == '.').count();



9> Peter Lawrey..:

一个较短的例子是

String text = "a.b.c.d";
int count = text.split("\\.",-1).length-1;


这个似乎有一个相对较大的开销,被警告它可能会创建很多小字符串.通常这并不重要,但要小心使用.

10> Yonatan Mama..:

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

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


除非您的字符串太长,否则会出现OutOfMemoryError.
大声笑,所以没有必要。

11> 0xCAFEBABE..:

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

for(int i=0;i

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



12> Jon Skeet..:

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


如果您的方法返回对自身的调用(包括运行的total参数),则更有可能获得尾递归,而不是返回执行添加的结果.

13> Tom Hawtin -..:

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



14> KannedFarU..:

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

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


要计算字符串末尾的出现次数,你必须使用负限制参数调用split,如下所示:`return(content.split(target,-1).length - 1);`.默认情况下,在split()导致的数组中省略了字符串末尾的出现.参见[Doku](http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String%29)

15> Alexis C...:

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

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



16> gil.fernande..:

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

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

输出:

3



17> Benny Neugeb..:

完整样本:

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



18> Amar Magar..:

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

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


对于给定的输入“ abc”,此代码段未返回正确数量的点

19> 小智..:

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



20> user3322553..:

split()仅需一行代码即可使用该功能

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


该解决方案将不包括尾随的空匹配,因为在此重载的拆分方法调用中,参数“ limit”被设置为零。例如:`“ 1 ## 2#3 #####”。split(“#”)`将仅产生大小为4的数组([[0:“ 1”; 1:“”; 2:“ 2“; 3:” 3“]`),而不是9(`[0:” 1“; 1:”“; 2:” 2“; 3:” 3“; 4:”“; 5:”“; 6:“”; 7:“”; 8:“”]`)。
推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有