web-dev-qa-db-fra.com

Comment compter le nombre d'occurrences d'un caractère dans une chaîne?

J'ai la ficelle

a.b.c.d

Je veux compter les occurrences de '.' de manière idiomatique, de préférence un one-liner.

(Auparavant, j'avais exprimé cette contrainte comme "sans boucle", au cas où vous vous demanderiez pourquoi tout le monde essaie de répondre sans utiliser de boucle).

504
Bart

Mon "one-liner" idiomatique pour cela est:

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

Pourquoi l'écrire vous-même quand il est déjà dans commons lang ?

Oneliner de Spring Framework pour cela est:

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

Que dis-tu de ça. Il n'utilise pas l'expression rationnelle sous-jacente, il devrait donc être plus rapide que d'autres solutions et ne pas utiliser de boucle.

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

Résumez une autre réponse et ce que je connais de toutes les façons de le faire en utilisant un seul support:

   String testString = "a.b.c.d";

1) Utiliser Apache Commons

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

2) Utilisation de Spring Framework

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

3) Utiliser remplacer

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

4) Utiliser replaceAll (cas 1)

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

5) Utiliser replaceAll (cas 2)

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

6) Utilisation de split

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

7) Utiliser Java8 (cas 1)

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

8) Utiliser Java8 (cas 2) peut être meilleur pour unicode que pour le cas 1

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

9) Utiliser StringTokenizer

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

Du commentaire : Attention au StringTokenizer, pour abcd cela fonctionnera mais pour un ... bc ... d ou ... abcd ou un .... b ...... c ..... d ... ou etc. cela ne fonctionnera pas. Cela comptera pour. entre les personnages juste une fois

Plus d'infos dans github

Test de performance (avec JMH , mode = Temps moyen, score 0.010 meilleur 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
256
Viacheslav Vedenin

Tôt ou tard, quelque chose doit boucler. C'est beaucoup plus simple pour vous d'écrire la boucle (très simple) que d'utiliser quelque chose comme split qui est beaucoup plus puissant que nécessaire.

Bien entendu, encapsulez la boucle dans un procédé séparé, par ex.

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

Dans ce cas, vous n'avez pas besoin de la boucle dans votre code principal - mais la boucle doit être présente quelque part.

170
Jon Skeet

J'ai eu une idée similaire à Mladen, mais l'inverse ...

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

ReplaceAll (".") Remplacerait tous les caractères.

La solution de PhiLho utilise ReplaceAll ("[^.]", ""), Qui n'a pas besoin d'être échappé, car [.] Représente le caractère "point", pas "n'importe quel caractère".

35
Mladen Prajdic

Ma solution "one-liner" idiomatique:

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

Vous ne savez pas pourquoi une solution utilisant StringUtils est acceptée.

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

Un exemple plus court est

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

voici une solution sans boucle:

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

eh bien, il y a une boucle, mais c'est invisible :-)

- Yonatan

17
Yonatan Maman

Je n'aime pas l'idée d'attribuer une nouvelle chaîne à cette fin. Et comme la chaîne a déjà un tableau de caractères à l'arrière où elle stocke sa valeur, String.charAt () est pratiquement libre.

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

fait l'affaire, sans attributions supplémentaires nécessitant une collecte, en 1 ligne ou moins, avec uniquement J2SE.

14
0xCAFEBABE

Ok, inspiré de la solution de Yonatan, en voici une qui est purement récursive - les seules méthodes de bibliothèque utilisées sont length() et charAt(), qui ne font aucune boucle:

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

Que la récursivité compte ou non en boucle dépend de la définition exacte que vous utilisez, mais elle est probablement aussi proche que possible.

Je ne sais pas si la plupart des machines virtuelles font la récursion de la queue ces jours-ci ... sinon, vous obtiendrez le débordement de pile éponyme pour des chaînes suffisamment longues, bien sûr.

13
Jon Skeet

Inspiré de Jon Skeet, une version sans boucle qui ne fera pas sauter votre pile. Point de départ également utile si vous souhaitez utiliser le framework 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);
    }
}

(Avertissement: non testé, non compilé, non raisonnable.)

Peut-être le meilleur moyen de l'écrire (avec un seul thread, sans support de paire de substitution):

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

Pas sûr de l'efficacité de ceci, mais c'est le code le plus court que j'ai pu écrire sans faire appel à des bibliothèques tierces:

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

Avec Java-8 , vous pouvez également utiliser des flux pour y parvenir. Évidemment, il y a une itération dans les coulisses, mais vous n'avez pas à l'écrire explicitement!

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
9
Alexis C.

Il est également possible d'utiliser une réduction dans Java 8 pour résoudre ce problème:

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

Sortie:

3
8
gil.fernandes

échantillon complet:

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

Appel:

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

Le moyen le plus simple d'obtenir la réponse est le suivant:

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

Si vous utilisez un framework Spring, vous pouvez également utiliser la classe "StringUtils". La méthode serait "countOccurrencesOf".

5
user496208

Vous pouvez utiliser la fonction split() en un seul code de ligne

int noOccurence=string.split("#",-1).length-1;
5
user3322553
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
kassim
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;
}
3
Hardest

Bien que les méthodes puissent le masquer, il n’ya aucun moyen de compter sans une boucle (ou une récursion). Vous souhaitez cependant utiliser un caractère [] pour des raisons de performances.

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

Utiliser replaceAll (c'est-à-dire RE) ne semble pas être la meilleure solution.

3
tcurdt

Pourquoi ne pas simplement diviser sur le caractère et ensuite obtenir la longueur du tableau résultant. la longueur du tableau sera toujours le nombre d'instances + 1. Pas vrai?

2
Darryl Price

Eh bien, avec une tâche assez similaire, je suis tombé sur ce fil. Je n'ai vu aucune restriction de langage de programmation et, depuis que groovy est exécuté sur un Java vm: Voici comment j'ai pu résoudre mon problème en utilisant Groovy.

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

terminé.

2
Christoph Zabinski

Utilisation de Eclipse Collections

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

Si vous devez compter plus d'un caractère, vous pouvez utiliser un CharBag comme suit:

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

Remarque: je suis un partisan des collections Eclipse.

2
Donald Raab
int count = (line.length() - line.replace("str", "").length())/"str".length();
2
Shaban

Voici une solution de récursion de style légèrement différente:

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
Stephen Denne

Le code source suivant ne vous donnera pas le nombre d'occurrences d'une chaîne donnée dans un mot entré par l'utilisateur: -

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
Shubham

Quelque part dans le code, quelque chose doit boucler. Le seul moyen de contourner ce problème est de dérouler complètement la boucle:

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

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


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

... etc., mais c'est vous qui faites la boucle manuellement dans l'éditeur de code source, au lieu de l'ordinateur qui l'exécutera. Voir le pseudocode:

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
Piskvor

Essayez cette méthode:

StringTokenizer stOR = new StringTokenizer(someExpression, "||");
int orCount = stOR.countTokens()-1;
1
BeeCreative
String[] parts = text.split(".");
int occurances = parts.length - 1;

" It's a great day at O.S.G. Dallas! "
     -- Famous Last Words

Eh bien, il s'agit de connaître votre Java, en particulier votre compréhension de base des classes de collection déjà disponibles en Java. Si vous parcourez l'intégralité de l'article, il y a à peu près tout, sauf l'explication de Stephen Hawking sur l'origine de l'univers, le livre de poche de Darwin sur Evolution et la sélection de casting de Gene Roddenberry dans Star Trek pour expliquer pourquoi ils sont allés avec William Shatner. ceci rapidement et facilement ...

... dois-je en dire plus?

1
Perry Anderson

Je vois beaucoup de trucs et de telles utilisations. Maintenant, je ne suis pas contre les belles astuces mais personnellement j'aime appeler simplement les méthodes qui sont signifiées pour faire le travail, alors j'ai créé encore une autre répondre.

Notez que si les performances posent problème, utilisez plutôt réponse de Jon Skeet . Celui-ci est un peu plus généralisé et donc légèrement plus lisible à mon avis (et bien sûr, réutilisable pour les chaînes et les patterns).

public static int countOccurances(char c, String input) {
    return countOccurancesOfPattern(Pattern.quote(Character.toString(c)), input);
}

public static int countOccurances(String s, String input) {
    return countOccurancesOfPattern(Pattern.quote(s), input);
}

public static int countOccurancesOfPattern(String pattern, String input) {
    Matcher m = Pattern.compile(pattern).matcher(input);
    int count = 0;
    while (m.find()) {
        count++;
    }
    return count;
}
1
Maarten Bodewes

Pourquoi essayez-vous d'éviter la boucle? Je veux dire que vous ne pouvez pas compter les points "numberOf" sans vérifier chaque caractère de la chaîne, et si vous appelez une fonction, elle se mettra en boucle. En d’autres termes, String.replace doit effectuer une boucle pour vérifier si la chaîne apparaît afin de pouvoir remplacer chaque occurrence.

Si vous essayez de réduire l'utilisation des ressources, vous ne le ferez pas comme cela, car vous créez une nouvelle chaîne simplement pour compter les points.

Maintenant, si nous parlons de la méthode récursive "entrer le code ici", quelqu'un a dit que cela échouerait à cause d'une exception OutOfMemmoryException, je pense qu'il a oublié StackOverflowException.

Donc ma méthode serait comme ça (je sais que c'est comme les autres mais, ce problème nécessite la boucle):

public static int numberOf(String str,int c) {
    int res=0;
    if(str==null)
        return res;
    for(int i=0;i<str.length();i++)
        if(c==str.charAt(i))
            res++;
    return res;
}
1
Sergio
 public static int countSubstring(String subStr, String str) {

    int count = 0;
    for (int i = 0; i < str.length(); i++) {
        if (str.substring(i).startsWith(subStr)) {
            count++;
        }
    }
    return count;
}
1
Adrian

En utilisant Java 8 et un HashMap sans aucune bibliothèque pour compter tous les différents caractères:

private static void countChars(String string) {
    HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
    string.chars().forEach(letter -> hm.put(letter, (hm.containsKey(letter) ? hm.get(letter) : 0) + 1));
    hm.forEach((c, i) -> System.out.println(((char)c.intValue()) + ":" + i));
}
0
Niklas Lyszio

Si vous voulez compter le non. du même caractère dans une chaîne 'Selenium' ou si vous souhaitez imprimer les caractères uniques de la chaîne 'Selenium'.

public class Count_Characters_In_String{

     public static void main(String []args){

        String s = "Selenium";
        System.out.println(s);
        int counter;

       String g = "";

        for( int i=0; i<s.length(); i++ ) { 

        if(g.indexOf(s.charAt(i)) == - 1){
           g=g+s.charAt(i); 
          }

       }
       System.out.println(g + " ");



        for( int i=0; i<g.length(); i++ ) {          
          System.out.print(",");

          System.out.print(s.charAt(i)+ " : ");
          counter=0; 
          for( int j=0; j<s.length(); j++ ) { 

        if( g.charAt(i) == s.charAt(j) ) {
           counter=counter+1;

           }      

          }
          System.out.print(counter); 
       }
     }
}

/ ******************** OUTPUT ********************* /

Sélénium

SELNIUM

S: 1, E: 2, L: 1, E: 1, N: 1, I: 1, U: 1.

0
Ashish Jaiswal

Essayez ce code:

package com.Java.test;

import Java.util.HashMap;
import Java.util.Map;

public class TestCuntstring {

    public static void main(String[] args) {

        String name = "Bissssmmayaa";
        char[] ar = new char[name.length()];
        for (int i = 0; i < name.length(); i++) {
            ar[i] = name.charAt(i);
        }
        Map<Character, String> map=new HashMap<Character, String>();
        for (int i = 0; i < ar.length; i++) {
            int count=0;
            for (int j = 0; j < ar.length; j++) {
                if(ar[i]==ar[j]){
                    count++;
                }
            }
            map.put(ar[i], count+" no of times");
        }
        System.out.println(map);
    }

}
0

Qu'en est-il de l'algo récursif ci-dessous.Il s'agit également du temps linéaire.

import Java.lang.*;
import Java.util.*;

class longestSubstr{

public static void main(String[] args){
   String s="ABDEFGABEF";


   int ans=calc(s);

   System.out.println("Max nonrepeating seq= "+ans);

}

public static int calc(String s)
{//s.s
      int n=s.length();
      int max=1;
      if(n==1)
          return 1;
      if(n==2)
      {
          if(s.charAt(0)==s.charAt(1)) return 1;
          else return 2;


      }
      String s1=s;
    String a=s.charAt(n-1)+"";
          s1=s1.replace(a,"");
         // System.out.println(s+" "+(n-2)+" "+s.substring(0,n-1));
         max=Math.max(calc(s.substring(0,n-1)),(calc(s1)+1));


return max;
}


}


</i>
0
Arnab sen