Введение
В этом кратком руководстве вы узнаете, как обнаружить несколько слов в строке.
наш пример
Предположим, у нас есть строки:
String inputString = "hello there, william";
Наша задача — найти, содержит ли inputString слова «hello» и «william».
Итак, давайте поместим наши ключевые слова в массив:
String[] words = {"hello", "william"};
Кроме того, порядок слов не имеет значения, соответствие чувствительно к регистру.
Используйте String.contains()
Во-первых,Мы покажем, как использовать метод String.contains() для достижения нашей цели..
Давайте пройдемся по массиву ключевых слов и проверим вхождение каждого элемента в inputString:
public static boolean containsWords(String inputString, String[] items) {
boolean found = true;
for (String item : items) {
if (!inputString.contains(item)) {
found = false;
break;
}
}
return found;
}
Этот пример относительно прост, и хотя нам нужно написать больше кода, это решение работает быстро для простых случаев использования.
Используйте String.indexOf()
и использоватьString.contains()Решение метода аналогично, мы можем использоватьString.indexOf()Метод проверяет индекс ключевого слова. Для этого нам нужен приемinputStringи метод списка ключевых слов:
public static boolean containsWordsIndexOf(String inputString, String[] words) {
boolean found = true;
for (String word : words) {
if (inputString.indexOf(word) == -1) {
found = false;
break;
}
}
return found;
}
сказалindexOf()
Метод возвращает индекс слова внутри inputString. Когда у нас нет слов в тексте, индекс будет равен -1.
Используйте регулярные выражения
Теперь давайте используем регулярные выражения для сопоставления наших слов. Для этого мы будем использоватьPatternсвоего рода.
Во-первых, давайте определим строковые выражения. Поскольку нам нужно сопоставить два ключевых слова, мы построим наше правило регулярного выражения, используя два просмотра вперед:
Pattern pattern = Pattern.compile("(?=.*hello)(?=.*william)");
Для общего случая:
StringBuilder regexp = new StringBuilder();
for (String word : words) {
regexp.append("(?=.*").append(word).append(")");
}
После этого мы будем использоватьmatcher()
методfind()
Количество вхождений:
public static boolean containsWordsPatternMatch(String inputString, String[] words) {
StringBuilder regexp = new StringBuilder();
for (String word : words) {
regexp.append("(?=.*").append(word).append(")");
}
Pattern pattern = Pattern.compile(regexp.toString());
return pattern.matcher(inputString).find();
}
но,Регулярные выражения имеют стоимость производительности. Это решение может работать неоптимально, если мы ищем несколько слов.
Использование Java 8 и списка
Наконец, мы можем использовать Stream API Java 8. Но сначала необходимо выполнить несколько простых преобразований исходных данных:
List<String> inputString = Arrays.asList(inputString.split(" "));
List<String> words = Arrays.asList(words);
Теперь пришло время использовать Stream API:
public static boolean containsWordsJava8(String inputString, String[] words) {
List<String> inputStringList = Arrays.asList(inputString.split(" "));
List<String> wordsList = Arrays.asList(words);
return wordsList.stream().allMatch(inputStringList::contains);
}
Приведенное выше вернется, если входная строка содержит все наши ключевые слова.true.
или,Мы можем просто использовать фреймворк CollectionscontainsAll()
методдля достижения желаемого результата:
public static boolean containsWordsArray(String inputString, String[] words) {
List<String> inputStringList = Arrays.asList(inputString.split(" "));
List<String> wordsList = Arrays.asList(words);
return inputStringList.containsAll(wordsList);
}
Однако этот метод работает только для целых слов. Таким образом, наши ключевые слова будут найдены только в том случае, если они разделены пробелами в тексте.
Использование алгоритма Ахо-Корасика
короче,Алгоритм Ахо-Корасика используется для текстового поиска с использованием нескольких ключевых слов. Независимо от того, сколько ключевых слов мы ищем или насколько длинным является текст, онO(n)
временная сложность
впусти наспом.xmlВключают Зависимости алгоритма Ахо-Корасика:
<dependency>
<groupId>org.ahocorasick</groupId>
<artifactId>ahocorasick</artifactId>
<version>0.4.0</version>
</dependency>
Во-первых, введите пакет зависимостей через maven, внутренняя структура будет использовать древовидную структуру данных:
Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();
После этого вызовем метод парсера с текстом inputString, в котором мы хотим найти ключевое слово, и сохраним результат в коллекции emits:
Collection<Emit> emits = trie.parseText(inputString);
Наконец, распечатайте результат запуска:
emits.forEach(System.out::println);
Для каждого ключевого слова мы ищем в тексте, где ключевое слово начинается, где оно заканчивается, и само ключевое слово:
0:4=hello
13:19=william
Наконец, давайте посмотрим на полную реализацию:
public static boolean containsWordsAhoCorasick(String inputString, String[] words) {
Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();
Collection<Emit> emits = trie.parseText(inputString);
emits.forEach(System.out::println);
boolean found = true;
for(String word : words) {
boolean contains = Arrays.toString(emits.toArray()).contains(word);
if (!contains) {
found = false;
break;
}
}
return found;
}
В этом примере мы ищем только целые слова. Итак, если мы не только хотим соответствоватьinputString
и соответствоватьhelloBaeldung
, мы должны просто удалить свойство onlyWholeWords() из конвейера построителя Trie.
Кроме того, имейте в виду, что мы также удаляем повторяющиеся элементы из коллекции emits, поскольку для одного и того же ключевого слова может быть несколько совпадений.
в заключении
В этой статье мы узнали, как найти несколько ключевых слов в строке. также,Мы показываем примеры с использованием ядра JDK, а также библиотеки Aho-Corasick..