Java: Como faço para contar o número de ocorrências de um char em uma String?

Eu tenho a string

abcd 

Eu quero contar as ocorrências de ‘.’ de uma forma idiomática, de preferência um one-liner.

(Anteriormente, eu havia expressado essa restrição como “sem loop”, caso você esteja se perguntando por que todos estão tentando responder sem usar um loop).

Meu ‘idiota one-liner’ para isso é:

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

Por que escrever você mesmo quando já está em commons lang ?

O oneliner do Spring Framework para isso é:

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

Que tal agora. Ele não usa o regexp por baixo, portanto, deve ser mais rápido do que algumas das outras soluções e não usará um loop.

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

Resumir outra resposta e o que eu sei de todas as maneiras de fazer isso usando um one-liner:

  String testString = "abcd"; 

1) Usando o Apache Commons

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

2) Usando o Spring Framework

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

3) usando replace

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

4) Usando replaceAll (caso 1)

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

5) Usando replaceAll (caso 2)

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

6) Usando split

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

7) Usando o Java 8 (caso 1)

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

8) Usando o Java8 (caso 2), pode ser melhor para o unicode do que o caso 1

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

9) Usando o StringTokenizer

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

Do comentário : Tenha cuidado com o StringTokenizer, pois abcd funcionará, mas para um … bc … d ou … abcd ou a …. b …… c ….. d … ou etc. não funcionará. Apenas contará para. entre os personagens apenas uma vez

Mais informações no github

Teste de desempenho (usando JMH , mode = AverageTime, pontuação de 0.010 melhor que 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 

Mais cedo ou mais tarde, algo tem que fazer um loop. É muito mais simples escrever o loop (muito simples) do que usar algo como split que é muito mais poderoso do que o necessário.

Por todos os meios encapsular o loop em um método separado, por exemplo

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

Então você não precisa ter o loop em seu código principal - mas o loop tem que estar lá em algum lugar.

Eu tive uma ideia semelhante a Mladen, mas o oposto …

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

ReplaceAll (“.”) Substituiria todos os caracteres.

A solução de PhiLho usa ReplaceAll (“[^.]”, “”), Que não precisa ter escape, já que [.] Representa o caractere ‘ponto’, não ‘nenhum caractere’.

Minha solução “idiomática de uma linha”:

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

Não tenho idéia porque uma solução que usa StringUtils é aceita.

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

Um exemplo mais curto é

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

Aqui está uma solução sem um loop:

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

Bem, há um loop, mas é invisível 🙂

– Yonatan

Eu não gosto da idéia de alocar uma nova string para esse propósito. E como a string já tem uma matriz char na parte de trás onde ela armazena seu valor, String.charAt () é praticamente livre.

 for(int i=0;i 

faz o truque, sem alocações adicionais que precisam de coleta, em uma linha ou menos, com apenas J2SE.

Ok, inspirado pela solução de Yonatan, aqui está uma que é puramente recursiva – os únicos methods de biblioteca usados ​​são length() e charAt() , nenhum dos quais faz nenhum loop:

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

Se a recursion conta como loop depende de qual definição exata você usa, mas é provavelmente o mais próximo que você conseguirá.

Eu não sei se a maioria das JVMs faz uma recursion final hoje em dia … se não, você obterá o estouro de pilha de mesmo nome para seqüências de caracteres adequadamente longas, é claro.

Inspirado por Jon Skeet, uma versão não-loop que não vai explodir sua pilha. Também é útil como ponto de partida se você quiser usar a estrutura 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); } } 

(Aviso: Não testado, não compilado, não sensato.)

Talvez a melhor maneira (de um único encadeamento, sem suporte de par substituto) de escrevê-lo:

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

Não tenho certeza sobre a eficiência disso, mas é o código mais curto que eu poderia escrever sem trazer bibliotecas de terceiros:

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

Com o java-8 você também pode usar streams para conseguir isso. Obviamente, há uma iteração nos bastidores, mas você não precisa escrevê-la explicitamente!

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

Amostra completa:

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

Ligar:

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

A maneira mais simples de obter a resposta é a seguinte:

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

Caso você esteja usando o Spring framework, você também pode usar a class “StringUtils”. O método seria “countOccurrencesOf”.

Também é possível usar reduzir no Java 8 para resolver esse problema:

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

Saída:

 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 

Você pode usar a function split() em apenas um código de linha

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

Embora os methods possam ocultá-lo, não há como contar sem um loop (ou recursion). Você quer usar um char [] por motivos de desempenho.

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

Usando replaceAll (que é RE) não parece ser o melhor caminho a percorrer.

 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 

Bem, é um caso de conhecer seu Java, especialmente sua compreensão básica de base das classs de coleção já disponíveis em Java. Se você olhar toda a postagem aqui, há quase tudo menos do que a explicação de Stephen Hawking sobre a Origem do Universo, o livro de Darwin sobre Evolução e a seleção do casting de Star Trek de Gene Roddenberry sobre por que eles foram com William Shatner. isso de forma rápida e fácil …

… preciso dizer mais?

Em algum lugar no código, algo tem que fazer um loop. A única maneira de contornar isso é um desenrolar completo do loop:

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

… etc, mas então você é o único a fazer o loop, manualmente, no editor de código – em vez do computador que irá executá-lo. Veja o pseudocódigo:

 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 

Aqui está uma solução de recursion de estilo ligeiramente diferente:

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

Por que não apenas dividir o caractere e, em seguida, obter o comprimento da matriz resultante. comprimento da matriz será sempre o número de instâncias + 1. Certo?

O código-fonte a seguir lhe dará no.of ocorrências de uma determinada string em uma palavra digitada pelo usuário: –

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

Usando Coleções do Eclipse

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

Se você tiver mais de um caractere para contar, você pode usar um CharBag seguinte maneira:

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

Nota: Eu sou um committer para collections do Eclipse.