Вхождения подстроки в строку


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
Сид

он не останавливается для вас, потому что после достижения вашего условия остановки (lastIndex == -1) вы сбрасываете его, увеличивая значение lastIndex (lastIndex + = findStr.length ();)
Legna

Ответы:


84

Последняя строка создавала проблему. 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
Мораль здесь заключается в том, что если вы собираетесь написать ответ, сначала проверьте, написал ли уже кто-то такой же ответ. На самом деле нет никакой пользы в том, что один и тот же ответ появляется дважды, независимо от того, был ли ваш ответ скопирован или написан независимо.
Давуд ибн Карим

193

Как насчет использования 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();был помещен за скобки, что привело к бесконечному циклу (когда вхождения не было найдено, lastIndex всегда был 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
Ой, спасибо, приятно знать! Это научит меня читать маленькие строчки в javadoc ...
Лоран Грегуар

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
Пуджан Шривастава

Это решение не работает для этого случая: str = "Это тестовая \\ n \\ r строка", subStr = "\\ r", показывает 0 вхождений.
Максим Овсяников 01

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". Некоторые аналогичные ответы, представленные здесь, не используют Pattern, поэтому в таких случаях они не работают.
Максим Овсяников 01

Нет причин для регулярного выражения, использовать 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
Не работает, следует указать используемую зависимость.
Saikat

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

Этот метод ниже показывает, сколько раз подстрока повторяется на всей строке ur. Надеюсь, вам понадобится: -

    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

вот другое решение без использования регулярных выражений / шаблонов / сопоставителей или даже без использования 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 других опубликованных решения, его, вероятно, следует удалить
Джейсон Уиллер

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.