Java: подсчитать количество вхождений слова в строку

Введение

Подсчет количества вхождений слова в строку — довольно простая задача, но для этого есть несколько подходов. Вы также должны учитывать эффективность метода, так как вы, как правило, хотите использовать автоматизированные инструменты, когда не хотите выполнять ручную работу, т. е. когда область поиска велика.

В этом руководстве вы узнаете, как подсчитать количество вхождений слова в строку в Java:

String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";

Мы будем искать количество вхождений targetWord, С помощью String.split(), Collections.frequency() и регулярные выражения.

Подсчет вхождений слов в строке с помощью String.split ()

Самый простой способ подсчитать вхождение целевого слова в строку — разбить строку на каждое слово и выполнить итерацию по массиву, увеличивая значение wordCount на каждом матче. Обратите внимание, что если вокруг слова есть какие-либо знаки препинания, например wants. в конце предложения — простое разделение на уровне слов будет корректно трактовать wants и wants. как отдельные слова!

Чтобы обойти это, вы можете легко удалить все знаки препинания из предложения. до разделив его:

String[] words = searchText.replaceAll("p{Punct}", "").split(" ");

int wordCount = 0;
for (int i=0; i < words.length; i++)
    if (words[i].equals(targetWord))
        wordCount++;
System.out.println(wordCount);

В for цикла, мы просто перебираем массив, проверяя, равен ли элемент по каждому индексу targetWord. Если это так, мы увеличиваем wordCount, который в конце выполнения выводит:

2

Подсчет вхождений слов в строке с помощью Коллекции.частота()

Ассоциация Collections.frequency() метод обеспечивает гораздо более чистую реализацию более высокого уровня, которая абстрагирует простой for цикла и проверяет как идентичность (является ли объект is другой предмет) и равенство (равнозначность предмета другому предмету в зависимости от качественных признаков этого предмета).

Ассоциация frequency() метод принимает список для поиска и целевой объект, а также работает для всех других объектов, где поведение зависит от того, как реализуется сам объект equals(). В случае строк, equals() проверяет наличие содержимое строки:


searchText = searchText.replaceAll("p{Punct}", "");

int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);

Здесь мы преобразовали массив, полученный из split() в Java ArrayList, с помощью помощника asList() метод Arrays учебный класс. Операция редукции frequency() возвращает целое число, обозначающее частоту targetWord в списке и приводит к:

2

Встречаемость слова в строке с Сопоставитель (Регулярные выражения — RegEx)

Наконец, вы можете использовать регулярные выражения для поиска шаблонов и подсчета количества совпадающих шаблонов. Для этого созданы регулярные выражения, так что они вполне подходят для этой задачи. В Яве Pattern класс используется для представления и компиляции регулярных выражений, а Matcher class используется для поиска и сопоставления шаблонов.

Используя RegEx, мы можем закодировать пунктуационную инвариантность в самом выражении, поэтому нет необходимости во внешнем форматировании строки или удалении пунктуации, что предпочтительнее для больших текстов, где хранение другой измененной версии в памяти может быть дорогостоящим:

Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));

Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);

int wordCount = 0;
while (matcher.find())
    wordCount++;

System.out.println(wordCount);

Это также приводит к:

2

Эталон эффективности

Итак, что является наиболее эффективным? Запустим небольшой бенчмарк:

int runs = 100000;

long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithSplit(searchText, targetWord);
}

long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));

long start2 = System.currentTimeMillis();
  for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithCollections(searchText, targetWord);
}

long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));

long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithRegex(searchText, targetWord);
}

long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));

Каждый метод будет запускаться 100000 раз (чем больше число, тем меньше дисперсия и результаты из-за случайности, из-за закона больших чисел). Запуск этого кода приводит к:

Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds

Однако — что произойдет, если мы сделаем поиск более затратным в вычислительном отношении, увеличив его? Сгенерируем синтетическое предложение:

List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();

for (int i = 0; i < 100; i++) {
    searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);

Это создает строку с содержимым:

hello world hello world hello world hello ...

Ознакомьтесь с нашим практическим руководством по изучению Git с рекомендациями, принятыми в отрасли стандартами и прилагаемой памяткой. Перестаньте гуглить команды Git и на самом деле изучить это!

Теперь, если бы мы искали «привет» или «мир» — совпадений было бы намного больше, чем два предыдущих. Как наши методы ведут себя сейчас в бенчмарке?

Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds

Теперь разбиение массива происходит быстрее всего! Как правило, тесты зависят от различных факторов, таких как пространство поиска, целевое слово и т. д., и ваш личный вариант использования может отличаться от теста.

Совет: Попробуйте методы на своем собственном тексте, отметьте время и выберите наиболее эффективный и элегантный для вас.

Заключение

В этом кратком руководстве мы рассмотрели, как подсчитывать количество вхождений слова для целевого слова в строке в Java. Мы начали с разделения строки и использования простого счетчика, а затем с помощью Collections вспомогательный класс и, наконец, использование регулярных выражений.

В конце концов, мы сравнили методы и отметили, что производительность не является линейной и зависит от области поиска. Для более длинных входных текстов с большим количеством совпадений разбиение массивов кажется наиболее эффективным. Попробуйте все три метода самостоятельно и выберите наиболее эффективный.

Отметка времени:

Больше от Стекабьюс