Проверете дали низът съдържа множество ключови думи в Java

1. Въведение

В този бърз урок ще разберем как да открием множество думи вътре в низ .

2. Нашият пример

Да предположим, че имаме низа:

String inputString = "hello there, Baeldung";

Нашата задача е да открием дали inputString съдържа думите „здравей“ и „Baeldung“ .

И така, нека поставим нашите ключови думи в масив:

String[] words = {"hello", "Baeldung"};

Освен това редът на думите не е важен и мачовете трябва да се отчитат с малки и големи букви.

3. Използване на 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; }

Методът contains () ще върне true, ако inputString съдържа дадения елемент . Когато нямаме нито една от ключовите думи в нашия низ, можем да спрем да се движим напред и да върнем незабавно false .

Въпреки факта, че трябва да напишем повече код, това решение е бързо за прости случаи на използване.

4. Използване на 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.

5. Използване на регулярни изрази

Сега, нека използваме регулярен израз, който да съвпада с нашите думи. За това ще използваме класа Pattern .

Първо, нека дефинираме низовия израз. Тъй като трябва да съпоставим две ключови думи, ще изградим нашето правило за регулярни изрази с две глави:

Pattern pattern = Pattern.compile("(?=.*hello)(?=.*Baeldung)");

И за общия случай:

StringBuilder regexp = new StringBuilder(); for (String word : words) { regexp.append("(?=.*").append(word).append(")"); }

След това ще използваме метода matcher () , за да намерим () случаите:

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

Но регулярните изрази имат разходи за производителност. Ако имаме няколко думи за търсене, ефективността на това решение може да не е оптимална.

6. Използване на Java 8 и List

И накрая, можем да използваме Java 8 Stream API. Но първо, нека направим някои малки трансформации с нашите първоначални данни:

List inputString = Arrays.asList(inputString.split(" ")); List words = Arrays.asList(words);

Сега е време да използваме Stream API:

public static boolean containsWordsJava8(String inputString, String[] words) { List inputStringList = Arrays.asList(inputString.split(" ")); List wordsList = Arrays.asList(words); return wordsList.stream().allMatch(inputStringList::contains); }

Конвейерът за операции по-горе ще върне вярно, ако входният низ съдържа всички наши ключови думи.

Като алтернатива можем просто да използваме метода containsAll () на рамката Collections, за да постигнем желания резултат:

public static boolean containsWordsArray(String inputString, String[] words) { List inputStringList = Arrays.asList(inputString.split(" ")); List wordsList = Arrays.asList(words); return inputStringList.containsAll(wordsList); }

Този метод обаче работи само за цели думи. Така че ще намери нашите ключови думи само ако са разделени с интервали в текста.

7. Използване на алгоритъма на Aho-Corasick

Най-просто казано, алгоритъмът Aho-Corasick е за търсене на текст с множество ключови думи . Той има O (n) времева сложност, независимо колко ключови думи търсим или колко дълга е дължината на текста.

Нека включим зависимостта на алгоритъма Aho-Corasick в нашия pom.xml :

 org.ahocorasick ahocorasick 0.4.0 

Първо, нека да строят синтактично дърво тръбопровода с думи набор от ключови думи. За това ще използваме структурата на данни Trie:

Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();

След това, нека да се обаждат на метода на анализатора с inputString текст, в който бихме искали да намерите ключовите думи и запишете резултатите в излъчва колекцията:

Collection emits = trie.parseText(inputString);

И накрая, ако отпечатаме нашите резултати:

emits.forEach(System.out::println);

За всяка ключова дума ще видим началната позиция на ключовата дума в текста, крайната позиция и самата ключова дума:

0:4=hello 13:20=Baeldung

И накрая, нека видим пълното изпълнение:

public static boolean containsWordsAhoCorasick(String inputString, String[] words) { Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build(); Collection 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 builder.

Освен това имайте предвид, че също така премахваме дублиращите се елементи от колекцията emits , тъй като може да има множество съвпадения за една и съща ключова дума.

8. Заключение

В тази статия научихме как да намерим множество ключови думи в низ. Освен това показахме примери, използвайки ядрото JDK, както и с библиотеката Aho-Corasick .

Както обикновено, пълният код за тази статия е достъпен в GitHub.