Виникнення підрядок у рядку


122

Чому наступний алгоритм не зупиняється для мене? (str - рядок, в якому я шукаю, findStr - рядок, яку я намагаюся знайти)

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

8
Ми зробили дійсно хороший в Udacity: ми використовували newSTR = str.replace (findStr, ""); і повернуто count = ((str.length () - newSTR.length ()) / findStr.length ());
SolarLunix

Схожий питання для персонажів: stackoverflow.com/q/275944/873282
koppor

Ви також не хочете враховувати випадок, коли префікс рядка пошуку є його суфіксом? У такому випадку я не думаю, що жодна із запропонованих відповідей спрацює. ось приклад. У цьому випадку вам знадобиться більш продуманий алгоритм, як Knuth Morris Pratt (KMP), кодований у книзі CLRS
Sid,

це не зупиняється для вас, оскільки після досягнення умови "зупинки" (lastIndex == -1) ви скидаєте його, збільшуючи значення lastIndex (lastIndex + = findStr.length ();)
Легна,

Відповіді:


83

Останній рядок створював проблему. lastIndexніколи не було б на -1, тому не було б нескінченного циклу. Це можна виправити, перемістивши останній рядок коду в блок 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);

121
Ця відповідь - це точна копія допису, яку я зробив за годину раніше;)
Олів’є

8
Зауважте, що це може або не повернути очікуваний результат. З підрядком "aa" та рядком для пошуку "aaa" кількість очікуваних випадків може бути одна (повертається цим кодом), але може бути і дві (у цьому випадку вам знадобиться "lastIndex ++" замість "lastIndex + = findStr.length () ") залежно від того, що ви шукаєте.
Станіслав Князєв

@olivier не бачив, що ... :( @stan це абсолютно правильно ... я просто виправляв код у проблемі ... здогадуйтесь, це залежить від того, що означає bobcom за кількістю зустрічей у рядку ...
codebreach

1
Коли люди навчаться загортати подібні речі в копію та вставляти статичний метод? Дивіться мою відповідь нижче, вона також більш оптимізована.
ммм

1
Мораль тут полягає в тому, що якщо ви збираєтесь написати відповідь, спочатку перевірте, чи хтось уже написав таку саму відповідь чи ні. Немає користі у тому, щоб однакова відповідь з’являлася двічі, незалежно від того, чи була ваша відповідь скопійована чи написана незалежно.
Давуд ібн Карім

192

Як щодо використання StringUtils.countMatches від Apache Commons Lang?

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

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

Це виводить:

3

9
Незалежно від того, наскільки ця пропозиція правильна, вона не може бути прийнята як рішення, оскільки не відповідає на питання ОП
kommradHomer

3
Це застаріле чи щось таке ... мій IDE не визнає
Вамсі Паван Махеш

@VamsiPavanMahesh StringUtils - це бібліотека Apache Commons. Перевірте тут: commons.apache.org/proper/commons-lang/javadocs/api-2.6/org / ...
Anup

Ця відповідь є копією відповіді Пітера Лорі на день раніше (див. Нижче).
Зона

StringUtilsне має countMatchesметоду.
плед-сорочка

117

Вас lastIndex += findStr.length();розміщували поза дужками, викликаючи нескінченну петлю (коли не було виявлено випадків, останній завжди був в цьому findStr.length()).

Ось виправлена ​​версія:

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

92

Більш коротка версія. ;)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
System.out.println(str.split(findStr, -1).length-1);

8
return haystack.split(Pattern.quote(needle), -1).length - 1;якщо, наприклад,needle=":)"
Mr_and_Mrs_D

2
@lOranger Без цього випаде ,-1кінцевий збіг.
Пітер Лодрі

3
О, дякую, добре знати! Це навчить мене читати маленькі рядки в Явадоку ...
Лоран Григоар

4
Приємно! Але це включає лише матчі, що не перетинаються, ні? Наприклад, відповідність "aa" у "aaa" поверне 1, а не 2? Звичайно, включаючи збіги, що перекриваються або не перекриваються, є дійсними і залежать від вимог користувача (можливо, прапор, який вказує на кількість перекриттів, так / ні)?
Корнел Массон

2
-1 .. спробуйте запустити це на "aaaa" та "aa" .. правильна відповідь 3, а не 2.
Kalyanaraman Santhanam

79

Вам справді доводиться самостійно обробляти відповідність? Особливо, якщо все, що вам потрібно, це кількість випадків, регулярні вирази витонченіші:

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

1
Тут НЕ знаходять спеціальних символів, вони знайдуть 0 підрахунків для рядків нижче: String str = "hel+loslkhel+lodjladfjhel+lo"; Pattern p = Pattern.compile("hel+lo");
Бен

13
так, це буде, якщо ви правильно висловите ваш регулярний вираз. спробуйте Pattern.compile("hel\\+lo");в +знак має особливого сенсу в регулярних виразах і повинен бути екранований.
Жан

4
Якщо ви шукаєте - взяти довільну рядок і використовувати її як точну відповідність зі всіма спеціальними символами регулярного вираження, ігнорованими, Pattern.quote(str)це ваш друг!
Майк Фуртак

2
це не працює для "aaa", коли str = "aaaaaa". Є 4 відповіді, але ваша відповідь дає 2
Pujan Srivastava

Це рішення не працює в цьому випадку: str = "Це тестовий \\ n \\ r рядок", subStr = "\\ r", він показує 0 входжень.
Максим Овсяніков

19

Я дуже здивований, що ніхто не згадав про цей лайнер. Це просто, стисло і виконує трохи краще, ніжstr.split(target, -1).length-1

public static int count(String str, String target) {
    return (str.length() - str.replace(target, "").length()) / target.length();
}

Повинно відповісти. Дякую!
lakam99

12

Ось він, завернутий у приємний та багаторазовий метод:

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

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

в кінці петлі кількість дорівнює 3; сподіваюся, що це допомагає


5
Код містить помилку. Якщо ми шукаємо одного символу, findStr.length() - 1повертається 0 і ми перебуваємо в нескінченному циклі.
Ян Боднар

6

Багато відповідей не відповідають одній або декільком з:

  • Шаблони довільної довжини
  • Матчі, що перекриваються (наприклад, підрахунок "232" у "23232" або "аа" в "ааа")
  • Метасимволи регулярного вираження

Ось що я написав:

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

Приклад виклику:

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

Якщо ви хочете шукати нерегулярні вирази, просто скомпілюйте свій шаблон відповідним чином із LITERALпрапором:

Pattern pattern = Pattern.compile("1+1", Pattern.LITERAL);
int count = countMatches(pattern, "1+1+1"); // Returns 2

Так ... здивований, що в Apache StringUtils такого подібного немає.
мійський гризун

6
public int countOfOccurrences(String str, String subStr) {
  return (str.length() - str.replaceAll(Pattern.quote(subStr), "").length()) / subStr.length();
}

Хороша відповідь. Чи можете ви проти додати деякі замітки про те, як це працює?
santhosh kumar

Звичайно, str - це наш рядок, subStr - це підрядка. Мета - обчислити кількість входів subStr на str. Для цього ми використовуємо формулу: (ab) / c, де a - довжина str, b - довжина str без усіх входів subStr (для цього видаляємо всі входження subStr з str), c - довжина subStr . Отже, в основному ми дістаємо з довжини str - довжину str без усього subStr, а потім ділимо результат на довжину subStr. Будь ласка, дайте мені знати, якщо у вас є інші питання.
Максим Овсяников

Сантош, ласкаво просимо! Важливою частиною є використання Pattern.quote для subStr, інакше в деяких випадках може вийти з ладу, наприклад у цьому: str = "Це тестовий \\ n \\ r рядок", subStr = "\\ r". Деякі подібні відповіді, надані тут, не використовують шаблон, тому в таких випадках вони не зможуть.
Максим Овсясіков

Причин для регулярного вираження, використання replace, немає replaceAll.
NateS

3

Збільшення lastIndexкожного разу, коли ви шукаєте наступного явища.

Інакше завжди знаходить першу підрядку (у позиції 0).


3
public int indexOf(int ch,
                   int fromIndex)

Повертає індекс всередині цього рядка першого появи вказаного символу, починаючи пошук за вказаним індексом.

Тому ваше lastindexзначення завжди дорівнює 0, і воно завжди знаходить привіт у рядку.


2

Відповідь, подана як правильна, не корисна для підрахунку таких речей, як повернення рядка, і є занадто багатослівною. Пізніші відповіді краще, але все можна досягти просто

str.split(findStr).length

Він не відкидає проміжні збіги, використовуючи приклад у питанні.


1
Це вже висвітлено в іншій відповіді ; і ця відповідь зробила це і краще.
michaelb958 - GoFundMonica

1
Це має бути коментар до відповіді, а не інша відповідь.
james.garriss

2

За допомогою вбудованої бібліотеки ви можете кількість випадків:

import org.springframework.util.StringUtils;
StringUtils.countOccurrencesOf(result, "R-")

1
Не працює, слід вказати залежність, яку ви використовували.
Сайкат

1

спробуйте додати lastIndex+=findStr.length()до кінця циклу, інакше ви опинитесь у нескінченному циклі, оскільки, знайшовши підрядку, ви намагаєтесь знайти її знову і знову з тієї ж останньої позиції.


1

Спробуйте це. Він замінює всі сірники на -.

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

І якщо ви не хочете знищувати свою, strви можете створити нову рядок з тим самим вмістом:

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

Після виконання цього блоку це будуть ваші значення:

str = "helloslkhellodjladfjhello"
strDestroy = "-slk-djladfj-"
findStr = "hello"
numberOfMatches = 3

1

Як @Mr_and_Mrs_D запропонував:

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

1

Виходячи з існуючих відповідей, я хотів би додати "коротшу" версію без if:

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

ця враховується, якщо рядок повторюється, наприклад, якщо ви шукаєте рядок "xx" у рядку "xxx".
tCoe

1

Ось розширена версія підрахунку, скільки разів маркер траплявся в рядок, що вводиться користувачем:

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

}

1

Цей нижче метод показує, скільки разів повторюється підрядка на ур цілому рядку. Сподіваюсь, вам сповна скористатися:

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

    }

0

ось інше рішення, не використовуючи regexp / pattern / matchers або навіть не використовуючи 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);

0

Якщо вам потрібен індекс кожної підрядки в початковому рядку, ви можете зробити щось з indexOf, як це:

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

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;

}


цьому питанню 8 років, і без жодних вказівок, чому це краще рішення, ніж розміщені 22 інші рішення, його, ймовірно, слід усунути
Jason Wheeler

0

Це рішення друкує загальну кількість зустрічей даної підрядки у всій рядку, також включає випадки, коли збіги, що перекриваються, існують.

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);
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.