Verifique se uma string contém várias palavras-chave
1. Introduction
Neste tutorial rápido,we’ll find out how to detect multiple words inside of a string.
2. Nosso exemplo
Vamos supor que temos a string:
String inputString = "hello there, example";
Nossa tarefa é descobrir seinputString contém as palavras“hello”e“example”.
Então, vamos colocar nossas palavras-chave em uma matriz:
String[] words = {"hello", "example"};
Além disso, a ordem das palavras não é importante e as correspondências devem diferenciar maiúsculas de minúsculas.
3. UsandoString.contains()
Para começar,we’ll show how to use the String.contains() method to achieve our goal.
Vamos percorrer a matriz de palavras-chave e verificar a ocorrência de cada item dentro doinputString:
public static boolean containsWords(String inputString, String[] items) {
boolean found = true;
for (String item : items) {
if (!inputString.contains(item)) {
found = false;
break;
}
}
return found;
}
O métodocontains() retornarátrue seinputString contiver oitem fornecido. Quando não temos nenhuma palavra-chave dentro de nossa string, podemos parar de avançar e retornar umfalse imediato.
Apesar do fato de que precisamos escrever mais código, esta solução é rápida para casos de uso simples.
4. UsandoString.indexOf()
Semelhante à solução que usa o métodoString.contains(),we can check the indices of the keywords by using the String.indexOf() method. Para isso, precisamos de um método que aceite oinputStringe a lista de palavras-chave:
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;
}
O métodoindexOf() retorna o índice da palavra dentro deinputString. Quando não temos a palavra no texto, o índice será -1.
5. Usando expressões regulares
Agora, vamos usar umregular expression para combinar nossas palavras. Para isso, usaremos a classePattern.
Primeiro, vamos definir a expressão da string. Como precisamos combinar duas palavras-chave, construiremos nossa regra regex com dois lookaheads:
Pattern pattern = Pattern.compile("(?=.*hello)(?=.*example)");
E para o caso geral:
StringBuilder regexp = new StringBuilder();
for (String word : words) {
regexp.append("(?=.*").append(word).append(")");
}
Depois disso, usaremos o métodomatcher() parafind() as ocorrências:
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();
}
Mas,regular expressions have a performance cost. If we have multiple words to look up, the performance of this solution might not be optimal.
6. Usando Java 8 eList
E, finalmente, podemos usarStream API do Java 8. Mas, primeiro, vamos fazer algumas pequenas transformações com nossos dados iniciais:
List inputString = Arrays.asList(inputString.split(" "));
List words = Arrays.asList(words);
Agora, é hora de usar a API Stream:
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);
}
O pipeline de operação acima retornarátrue se a string de entrada contiver todas as nossas palavras-chave.
Alternativamente,we can simply use the containsAll() method of the Collections framework para atingir o resultado desejado:
public static boolean containsWordsArray(String inputString, String[] words) {
List inputStringList = Arrays.asList(inputString.split(" "));
List wordsList = Arrays.asList(words);
return inputStringList.containsAll(wordsList);
}
No entanto, esse método funciona apenas para palavras inteiras. Portanto, ele encontraria nossas palavras-chave apenas se elas estivessem separadas por um espaço em branco no texto.
7. Usando o AlgoritmoAho-Corasick
Simplificando, oAho-Corasick algorithm is for text searching with multiple keywords. It has O(n) time complexity no matter how many keywords we’re searching for or how long the text length is.
Vamos incluir oAho-Corasick algorithm dependency em nossopom.xml:
org.ahocorasick
ahocorasick
0.4.0
Primeiro, vamos construir o pipeline de teste com a matrizwords de palavras-chave. Para isso, usaremos a estrutura de dadosTrie:
Trie trie = Trie.builder().onlyWholeWords().addKeywords(words).build();
Depois disso, vamos chamar o método parser com o textoinputString no qual gostaríamos de encontrar as palavras-chave e salvar os resultados na coleçãoemits:
Collection emits = trie.parseText(inputString);
E, finalmente, se imprimirmos nossos resultados:
emits.forEach(System.out::println);
Para cada palavra-chave, veremos a posição inicial da palavra-chave no texto, a posição final e a própria palavra-chave:
0:4=hello
13:20=example
Finalmente, vamos ver a implementação completa:
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;
}
Neste exemplo, procuramos apenas palavras inteiras. Portanto, se quisermos corresponder não apenasinputString, mas também“helloexample”, devemos simplesmente remover o atributoonlyWholeWords() do pipeline de construtorTrie.
Além disso, lembre-se de que também removemos os elementos duplicados da coleçãoemits, pois pode haver várias correspondências para a mesma palavra-chave.
8. Conclusão
Neste artigo, aprendemos como encontrar várias palavras-chave dentro de uma string. Além disso,we showed examples by using the core JDK, as well as with the Aho-Corasick library.
Como de costume, o código completo deste artigo está disponívelover on GitHub.