Advanced Advanced Проверка наличия в строке нескольких ключевых слов

Java

Введение

В этом кратком руководстве вы узнаете, как обнаружить несколько слов в строке.

наш пример

Предположим, у нас есть строки:

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..