Occurrences de sous-chaîne dans une chaîne

122

Pourquoi l'algorithme suivant ne s'arrête pas pour moi? (str est la chaîne dans laquelle je recherche, findStr est la chaîne que j'essaie de trouver)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while (lastIndex != -1) {
    lastIndex = str.indexOf(findStr,lastIndex);

    if( lastIndex != -1)
        count++;

    lastIndex += findStr.length();
}

System.out.println(count);
Robert Harvey
la source
8
Nous en avons fait un très bon dans Udacity: nous avons utilisé newSTR = str.replace (findStr, ""); et a renvoyé count = ((str.length () - newSTR.length ()) / findStr.length ());
SolarLunix
Question similaire pour les personnages: stackoverflow.com/q/275944/873282
koppor
Ne voulez-vous pas également tenir compte du cas où le préfixe de la chaîne de recherche est son suffixe? Dans ce cas, je ne pense pas qu'aucune des réponses suggérées ne fonctionnerait. voici un exemple. Dans ce cas, vous auriez besoin d'un algorithme plus élaboré, comme le Knuth Morris Pratt (KMP) qui est codé dans le livre CLRS
Sid
il ne s'arrête pas pour vous, car après avoir atteint votre condition `` d'arrêt '' (lastIndex == -1), vous le réinitialisez en incrémentant la valeur de lastIndex (lastIndex + = findStr.length ();)
Legna

Réponses:

83

La dernière ligne créait un problème. lastIndexne serait jamais à -1, donc il y aurait une boucle infinie. Cela peut être résolu en déplaçant la dernière ligne de code dans le bloc if.

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while(lastIndex != -1){

    lastIndex = str.indexOf(findStr,lastIndex);

    if(lastIndex != -1){
        count ++;
        lastIndex += findStr.length();
    }
}
System.out.println(count);
codebreach
la source
121
Cette réponse est la copie exacte du message que j'ai fait une heure avant;)
Olivier
8
Notez que cela peut renvoyer ou non le résultat attendu. Avec la sous-chaîne "aa" et la chaîne pour rechercher "aaa", le nombre d'occurrences attendues peut être un (renvoyé par ce code), mais peut également être deux (dans ce cas, vous aurez besoin de "lastIndex ++" au lieu de "lastIndex + = findStr.length () ") en fonction de ce que vous recherchez.
Stanislav Kniazev
@olivier n'a pas vu ça ... :( @stan c'est absolument correct ... je réparais juste le code dans le problème ... je suppose que cela dépend de ce que bobcom entend par nombre d'occurrences dans la chaîne ...
codebreach
1
Quand les gens vont-ils apprendre à emballer des choses comme celle-ci dans une méthode statique de copier-coller? Voir ma réponse ci-dessous, elle est également plus optimisée.
mmm
1
La morale ici est que si vous avez l'intention d'écrire une réponse, vérifiez d' abord si quelqu'un d'autre a déjà écrit exactement la même réponse. Il n'y a vraiment aucun avantage à faire apparaître la même réponse deux fois, que votre réponse ait été copiée ou écrite indépendamment.
Dawood ibn Kareem le
192

Que diriez-vous d'utiliser StringUtils.countMatches d'Apache Commons Lang?

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

System.out.println(StringUtils.countMatches(str, findStr));

Cela produit:

3
UN M
la source
9
Aussi
3
Est-ce obsolète ou quelque chose ... mon IDE ne reconnaît pas
Vamsi Pavan Mahesh
@VamsiPavanMahesh StringUtils est une bibliothèque d'Apache Commons. Vérifiez ici: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/…
Anup
Cette réponse est une copie de la réponse de Peter Lawrey un jour plus tôt (voir ci-dessous).
Zon
StringUtilsn'a pas de countMatchesméthode.
plaidshirt
117

Votre a lastIndex += findStr.length();été placé en dehors des crochets, provoquant une boucle infinie (quand aucune occurrence n'a été trouvée, lastIndex était toujours à findStr.length()).

Voici la version fixe:

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while (lastIndex != -1) {

    lastIndex = str.indexOf(findStr, lastIndex);

    if (lastIndex != -1) {
        count++;
        lastIndex += findStr.length();
    }
}
System.out.println(count);
Olivier
la source
92

Une version plus courte. ;)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
System.out.println(str.split(findStr, -1).length-1);
Peter Lawrey
la source
8
return haystack.split(Pattern.quote(needle), -1).length - 1;si par exempleneedle=":)"
Mr_and_Mrs_D
2
@lOranger Sans ,-1cela, les correspondances de fin seront supprimées .
Peter Lawrey
3
Aïe, merci, bon à savoir! Cela m'apprendra à lire les petites lignes dans le javadoc ...
Laurent Grégoire
4
Agréable! Mais cela n'inclut que les matchs sans chevauchement, non? Par exemple, la correspondance "aa" dans "aaa" renverra 1, pas 2? Bien sûr, les correspondances qui se chevauchent ou ne se chevauchent pas sont à la fois valides et dépendent des exigences de l'utilisateur (peut-être un indicateur pour indiquer les chevauchements de comptage, oui / non)?
Cornel Masson
2
-1 .. essayez d'exécuter ceci sur "aaaa" et "aa" .. la bonne réponse est 3 et non 2.
Kalyanaraman Santhanam
79

Devez-vous vraiment gérer la correspondance vous-même? Surtout si tout ce dont vous avez besoin est le nombre d'occurrences, les expressions régulières sont plus ordonnées:

String str = "helloslkhellodjladfjhello";
Pattern p = Pattern.compile("hello");
Matcher m = p.matcher(str);
int count = 0;
while (m.find()){
    count +=1;
}
System.out.println(count);     
Jean
la source
1
Cela ne trouve PAS de caractères spéciaux, il trouvera 0 compte pour les chaînes ci-dessous: String str = "hel+loslkhel+lodjladfjhel+lo"; Pattern p = Pattern.compile("hel+lo");
Ben
13
oui, ce sera le cas si vous exprimez correctement votre regex. essayer avec Pattern.compile("hel\\+lo");le +signe a une signification particulière dans une expression régulière et doit être échappé.
Jean
4
Si ce que vous cherchez est de prendre une chaîne arbitraire et de l'utiliser comme correspondance exacte avec tous les caractères spéciaux d'expressions régulières ignorés, Pattern.quote(str)c'est votre ami!
Mike Furtak
2
cela ne fonctionne pas pour "aaa" lorsque str = "aaaaaa". Il y a 4 réponses mais la vôtre en donne 2
Pujan Srivastava
Cette solution ne fonctionne pas dans ce cas: str = "Ceci est une chaîne de test \\ n \\ r", subStr = "\\ r", il affiche 0 occurrence.
Maksym Ovsianikov
19

Je suis très surpris que personne n'ait mentionné cette seule doublure. C'est simple, concis et fonctionne légèrement mieux questr.split(target, -1).length-1

public static int count(String str, String target) {
    return (str.length() - str.replace(target, "").length()) / target.length();
}
kmecpp
la source
Devrait être la meilleure réponse. Je vous remercie!
lakam99
12

Le voici, enveloppé dans une méthode agréable et réutilisable:

public static int count(String text, String find) {
        int index = 0, count = 0, length = find.length();
        while( (index = text.indexOf(find, index)) != -1 ) {                
                index += length; count++;
        }
        return count;
}
mmm
la source
8
String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while((lastIndex = str.indexOf(findStr, lastIndex)) != -1) {
     count++;
     lastIndex += findStr.length() - 1;
}
System.out.println(count);

à la fin du nombre de boucles, 3; J'espère que ça aide

dfa
la source
5
Le code contient une erreur. Si nous recherchons un seul caractère, le findStr.length() - 1retourne 0 et nous sommes dans un cycle sans fin.
Jan Bodnar
6

Un grand nombre des réponses données échouent sur un ou plusieurs des éléments suivants:

  • Modèles de longueur arbitraire
  • Correspondances qui se chevauchent (par exemple, compter "232" dans "23232" ou "aa" dans "aaa")
  • Méta-caractères d'expression régulière

Voici ce que j'ai écrit:

static int countMatches(Pattern pattern, String string)
{
    Matcher matcher = pattern.matcher(string);

    int count = 0;
    int pos = 0;
    while (matcher.find(pos))
    {
        count++;
        pos = matcher.start() + 1;
    }

    return count;
}

Exemple d'appel:

Pattern pattern = Pattern.compile("232");
int count = countMatches(pattern, "23232"); // Returns 2

Si vous voulez une recherche non-expression régulière, compilez simplement votre modèle de manière appropriée avec l' LITERALindicateur:

Pattern pattern = Pattern.compile("1+1", Pattern.LITERAL);
int count = countMatches(pattern, "1+1+1"); // Returns 2
benkc
la source
Oui ... surpris qu'il n'y ait pas quelque chose comme ça dans Apache StringUtils.
mike rodent
6
public int countOfOccurrences(String str, String subStr) {
  return (str.length() - str.replaceAll(Pattern.quote(subStr), "").length()) / subStr.length();
}
Maksym Ovsianikov
la source
Bonne réponse. Pouvez-vous ajouter quelques notes sur son fonctionnement?
santhosh kumar
Bien sûr, str - est notre chaîne source, subStr - est une sous-chaîne. Le but est de calculer le nombre d'occurrences de subStr dans str. Pour ce faire, nous utilisons la formule: (ab) / c, où a - longueur de str, b - longueur de str sans toutes les occurrences de subStr (nous supprimons toutes les occurrences de subStr de str pour cela), c - longueur de subStr . Donc, fondamentalement, nous extrayons de la longueur de str - longueur de str sans tout subStr, puis nous divisons le résultat sur la longueur de subStr. Veuillez me faire savoir si vous avez d'autres questions.
Maksym Ovsianikov
Santhosh, vous êtes les bienvenus! La partie importante est d'utiliser Pattern.quote pour subStr, sinon dans peut échouer dans certains cas, comme celui-ci: str = "Ceci est un test \\ n \\ r string", subStr = "\\ r". Certaines réponses similaires fournies ici n'utilisent pas Pattern, elles échoueront donc dans de tels cas.
Maksym Ovsianikov
Il n'y a aucune raison pour regex, utilisez replace, non replaceAll.
NateS
3

Incrémentez lastIndexchaque fois que vous recherchez la prochaine occurrence.

Sinon, il trouve toujours la première sous-chaîne (à la position 0).

Stanislav Kniazev
la source
3
public int indexOf(int ch,
                   int fromIndex)

Renvoie l'index dans cette chaîne de la première occurrence du caractère spécifié, en commençant la recherche à l'index spécifié.

Donc, votre lastindexvaleur est toujours 0 et elle trouve toujours bonjour dans la chaîne.

Bhushan Bhangale
la source
2

La réponse donnée comme correcte n'est pas bonne pour compter des choses comme les retours de ligne et est beaucoup trop verbeuse. Les réponses ultérieures sont meilleures mais tout peut être réalisé simplement avec

str.split(findStr).length

Il ne supprime pas les correspondances de fin en utilisant l'exemple de la question.

marque
la source
1
Cela a déjà été couvert dans une autre réponse ; et cette réponse l'a fait mieux aussi.
michaelb958 - GoFundMonica
1
Cela devrait être un commentaire sur la réponse en question, pas une autre réponse.
james.garriss
2

Vous pouvez nombre d'occurrences en utilisant la fonction de bibliothèque intégrée:

import org.springframework.util.StringUtils;
StringUtils.countOccurrencesOf(result, "R-")
Victor
la source
1
Ne fonctionne pas, vous devez spécifier la dépendance que vous avez utilisée.
Saikat
1

essayez d'ajouter lastIndex+=findStr.length()à la fin de votre boucle, sinon vous vous retrouverez dans une boucle sans fin car une fois que vous avez trouvé la sous-chaîne, vous essayez de la retrouver encore et encore à partir de la même dernière position.

Thorsten Schleinzer
la source
1

Essaye celui-là. Il remplace toutes les correspondances par un -.

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int numberOfMatches = 0;
while (str.contains(findStr)){
    str = str.replaceFirst(findStr, "-");
    numberOfMatches++;
}

Et si vous ne voulez pas détruire votre, strvous pouvez créer une nouvelle chaîne avec le même contenu:

String str = "helloslkhellodjladfjhello";
String strDestroy = str;
String findStr = "hello";
int numberOfMatches = 0;
while (strDestroy.contains(findStr)){
    strDestroy = strDestroy.replaceFirst(findStr, "-");
    numberOfMatches++;
}

Après avoir exécuté ce bloc, ce seront vos valeurs:

str = "helloslkhellodjladfjhello"
strDestroy = "-slk-djladfj-"
findStr = "hello"
numberOfMatches = 3
Alex
la source
1

Comme @Mr_and_Mrs_D l'a suggéré:

String haystack = "hellolovelyworld";
String needle = "lo";
return haystack.split(Pattern.quote(needle), -1).length - 1;
Ron Tesler
la source
1

Sur la base des réponses existantes, j'aimerais ajouter une version "plus courte" sans le si:

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

int count = 0, lastIndex = 0;
while((lastIndex = str.indexOf(findStr, lastIndex)) != -1) {
    lastIndex += findStr.length() - 1;
    count++;
}

System.out.println(count); // output: 3
sjkm
la source
celui-ci prend en compte si la chaîne se répète, par exemple si vous recherchez la chaîne «xx» dans une chaîne «xxx».
tCoe le
1

Voici la version avancée pour compter le nombre de fois où le jeton s'est produit dans une chaîne saisie par l'utilisateur:

public class StringIndexOf {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.println("Enter a sentence please: \n");
        String string = scanner.nextLine();

        int atIndex = 0;
        int count = 0;

        while (atIndex != -1)
        {
            atIndex = string.indexOf("hello", atIndex);

            if(atIndex != -1)
            {
                count++;
                atIndex += 5;
            }
        }

        System.out.println(count);
    }

}
Venzentx
la source
1

Cette méthode ci-dessous montre combien de fois la sous-chaîne se répète sur toute votre chaîne. J'espère utiliser pleinement pour vous: -

    String searchPattern="aaa"; // search string
    String str="aaaaaababaaaaaa"; // whole string
    int searchLength = searchPattern.length(); 
    int totalLength = str.length(); 
    int k = 0;
    for (int i = 0; i < totalLength - searchLength + 1; i++) {
        String subStr = str.substring(i, searchLength + i);
        if (subStr.equals(searchPattern)) {
           k++;
        }

    }
duggu
la source
0

voici l'autre solution sans utiliser regexp / patterns / matchers ou même sans utiliser StringUtils.

String str = "helloslkhellodjladfjhelloarunkumarhelloasdhelloaruhelloasrhello";
        String findStr = "hello";
        int count =0;
        int findStrLength = findStr.length();
        for(int i=0;i<str.length();i++){
            if(findStr.startsWith(Character.toString(str.charAt(i)))){
                if(str.substring(i).length() >= findStrLength){
                    if(str.substring(i, i+findStrLength).equals(findStr)){
                        count++;
                    }
                }
            }
        }
        System.out.println(count);
Arun Kumar Mudraboyina
la source
0

Si vous avez besoin de l'index de chaque sous-chaîne dans la chaîne d'origine, vous pouvez faire quelque chose avec indexOf comme ceci:

 private static List<Integer> getAllIndexesOfSubstringInString(String fullString, String substring) {
    int pointIndex = 0;
    List<Integer> allOccurences = new ArrayList<Integer>();
    while(fullPdfText.indexOf(substring,pointIndex) >= 0){
       allOccurences.add(fullPdfText.indexOf(substring, pointIndex));
       pointIndex = fullPdfText.indexOf(substring, pointIndex) + substring.length();
    }
    return allOccurences;
}
Rhinocéros
la source
0
public static int getCountSubString(String str , String sub){
int n = 0, m = 0, counter = 0, counterSub = 0;
while(n < str.length()){
  counter = 0;
  m = 0;
  while(m < sub.length() && str.charAt(n) == sub.charAt(m)){
    counter++;
    m++; n++;
  }
  if (counter == sub.length()){
    counterSub++;
    continue;
  }
  else if(counter > 0){
    continue;
  }
  n++;
}

return  counterSub;

}

Nikolai Nechai
la source
cette question a 8 ans, et sans aucune indication sur les raisons pour lesquelles c'est une meilleure solution que les 22 autres solutions publiées, elle devrait probablement être supprimée
Jason Wheeler
0

Cette solution imprime le nombre total d'occurrences d'une sous-chaîne donnée tout au long de la chaîne, inclut également les cas où des correspondances se chevauchent.

class SubstringMatch{
    public static void main(String []args){
        //String str = "aaaaabaabdcaa";
        //String sub = "aa";
        //String str = "caaab";
        //String sub = "aa";
        String str="abababababaabb";
        String sub = "bab";

        int n = str.length();
        int m = sub.length();

        // index=-1 in case of no match, otherwise >=0(first match position)
        int index=str.indexOf(sub), i=index+1, count=(index>=0)?1:0;
        System.out.println(i+" "+index+" "+count);

        // i will traverse up to only (m-n) position
        while(index!=-1 && i<=(n-m)){   
            index=str.substring(i, n).indexOf(sub);
            count=(index>=0)?count+1:count;
            i=i+index+1;  
            System.out.println(i+" "+index);
        }
        System.out.println("count: "+count);
    }
}
Anubhav Singh
la source