Maneira simples de contar as ocorrências de caracteres em uma string

Existe uma maneira simples (em vez de percorrer manualmente toda a string ou loop para indexOf) para descobrir quantas vezes um caractere aparece em uma string?

Digamos que temos “abdsd3 $ asda $ asasdd $ sadas” e queremos que $ apareça 3 vezes.

String s = "..."; int counter = 0; for( int i=0; i 

Este é definitivamente o caminho mais rápido. Regexes são muito mais lentos aqui e possivelmente mais difíceis de entender.

Estilo funcional (Java 8, apenas por diversão):

 str.chars().filter(num -> num == '$').count() 

Não é o melhor, mas uma maneira simples de contar ocorrências:

 String s = "..."; int counter = s.split("\\$", -1).length - 1; 

Nota:

  • Cifrão é um símbolo especial de Expressão Regular, por isso deve ser escapado com uma barra invertida.
  • Uma barra invertida é um símbolo especial para caracteres de escape, como novas linhas, portanto deve ser escapado com uma barra invertida.
  • O segundo argumento de divisão impede que seqüências de caracteres vazias vazias sejam removidas.

Você pode usar o StringUtils.countMatches(String string, String subStringToCount) Apache Commons StringUtils.countMatches(String string, String subStringToCount) .

Já que você está escaneando toda a string de qualquer maneira, você pode construir uma contagem completa de caracteres e fazer qualquer número de pesquisas, tudo pelo mesmo custo grande (n):

 public static Map getCharFreq(String s) { Map charFreq = new HashMap(); if (s != null) { for (Character c : s.toCharArray()) { Integer count = charFreq.get(c); int newCount = (count==null ? 1 : count+1); charFreq.put(c, newCount); } } return charFreq; } // ... String s = "abdsd3$asda$asasdd$sadas"; Map counts = getCharFreq(s); counts.get('$'); // => 3 counts.get('a'); // => 7 counts.get('s'); // => 6 

Uma contagem de frequência de caracteres é uma tarefa comum para alguns aplicativos (como educação), mas não geral o suficiente para garantir a inclusão com as principais APIs Java. Como tal, você provavelmente precisará escrever sua própria function.

Você também pode usar um para cada loop. Eu acho que é mais simples de ler.

 int occurrences = 0; for(char c : yourString.toCharArray()){ if(c == '$'){ occurrences++; } } 

Atravessar a string é provavelmente o mais eficiente, embora usar o Regex para fazer isso possa gerar um código mais limpo (embora você sempre possa ocultar seu código transversal em uma function).

Bem, há um monte de utilitários diferentes para isso, por exemplo, Apache Commons Lang String Utils

mas no final, ele tem que percorrer a string para contar as ocorrências de uma forma ou de outra.

Note também que o método countMatches acima possui a seguinte assinatura, assim também funcionará para substrings.

public static int countMatches(String str, String sub)

A fonte para isso é ( daqui ):

 public static int countMatches(String str, String sub) { if (isEmpty(str) || isEmpty(sub)) { return 0; } int count = 0; int idx = 0; while ((idx = str.indexOf(sub, idx)) != -1) { count++; idx += sub.length(); } return count; } 

Eu estava curioso se eles estavam interagindo com a string ou usando o Regex.

Eu acredito que o “one liner” que você esperava obter é este:

 "abdsd3$asda$asasdd$sadas".replaceAll( "[^$]*($)?", "$1" ).length(); 

Lembre-se de que os requisitos são:

(em vez de percorrer manualmente toda a string ou loop para indexOf )

e deixe-me acrescentar: que no centro desta questão parece que “qualquer loop” não é desejado e não há necessidade de velocidade. Eu acredito que o subtexto desta questão é fator de frescor .

Algo um pouco mais funcional, sem o Regex:

 public static int count(String s, char c) { return s.length()==0 ? 0 : (s.charAt(0)==c ? 1 : 0) + count(s.substring(1),c); } 

Não é uma cauda recursiva, por uma questão de clareza.

Você pode olhar para classificar a string – tratá-la como uma matriz char – e então fazer uma pesquisa binária modificada que conta as ocorrências? Mas eu concordo com @tofutim que a travessia é a mais eficiente – O (N) versus O (N * logN) + O (logN)

Este é um código simples, mas é claro, um pouco mais lento.

 String s = ...; int countDollar = s.length()-s.replaceAll("\\$","").length(); int counta = s.length()-s.replaceAll("a","").length(); 

Uma resposta ainda melhor está aqui em uma pergunta duplicada

Existe outra maneira de contar o número de caracteres em cada string. Assumindo que temos um String como String str = "abfdvdvdfv"

Podemos então contar o número de vezes que cada caractere aparece percorrendo apenas uma vez

 for (int i = 0; i < str.length(); i++) { if(null==map.get(str.charAt(i)+"")) { map.put(str.charAt(i)+"", new Integer(1)); } else { Integer count = map.get(str.charAt(i)+""); map.put(str.charAt(i)+"", count+1); } } 

Podemos então verificar a saída percorrendo o Mapa como

 for (Map.Entry entry:map.entrySet()) { System.out.println(entry.getKey()+" count is : "+entry.getValue()) } 
  public static int countChars(String input,char find){ if(input.indexOf(find) != -1){ return countChars(input.substring(0, input.indexOf(find)), find)+ countChars(input.substring(input.indexOf(find)+1),find) + 1; } else { return 0; } }