Removendo palavras irrelevantes de uma string em Java

Removendo palavras irrelevantes de uma string em Java

1. Visão geral

Neste tutorial, discutiremos diferentes maneiras de remover palavras irrelevantes deString em Java. Essa é uma operação útil nos casos em que queremos remover palavras indesejadas ou não permitidas de um texto, como comentários ou resenhas adicionadas por usuários de um site online.

Usaremos um loop simples,Collection.removeAll()e expressões regulares.

Finalmente, compararemos seu desempenho usandoJava Microbenchmark Harness.

2. Carregando palavras irrelevantes

Primeiro, vamos carregar nossas palavras irrelevantes de um arquivo de texto.

Aqui temos o arquivoenglish_stopwords.txt que contém uma lista de palavras que consideramos palavras irrelevantes, comoI,he,she ethe.

Vamos carregar as palavras irrelevantes emList deString usandoFiles.readAllLines():

@BeforeClass
public static void loadStopwords() throws IOException {
    stopwords = Files.readAllLines(Paths.get("english_stopwords.txt"));
}

3. Removendo palavras irrelevantes manualmente

Para nossa primeira solução,we’ll remove stopwords manually by iterating over each word and checking if it’s a stopword:

@Test
public void whenRemoveStopwordsManually_thenSuccess() {
    String original = "The quick brown fox jumps over the lazy dog";
    String target = "quick brown fox jumps lazy dog";
    String[] allWords = original.toLowerCase().split(" ");

    StringBuilder builder = new StringBuilder();
    for(String word : allWords) {
        if(!stopwords.contains(word)) {
            builder.append(word);
            builder.append(' ');
        }
    }

    String result = builder.toString().trim();
    assertEquals(result, target);
}

4. UsandoCollection.removeAll()

A seguir, em vez de iterar cada palavra em nossoString,we can use Collection.removeAll() to remove all stopwords at once:

@Test
public void whenRemoveStopwordsUsingRemoveAll_thenSuccess() {
    ArrayList allWords =
      Stream.of(original.toLowerCase().split(" "))
            .collect(Collectors.toCollection(ArrayList::new));
    allWords.removeAll(stopwords);

    String result = allWords.stream().collect(Collectors.joining(" "));
    assertEquals(result, target);
}

Neste exemplo, depois de dividir nossoString em uma matriz de palavras, vamos transformá-lo emArrayList para poder aplicar o métodoremoveAll().

5. Usando expressões regulares

Finalmente,we can create a regular expression from our stopwords list, então use-o para substituir palavras irrelevantes em nossoString:

@Test
public void whenRemoveStopwordsUsingRegex_thenSuccess() {
    String stopwordsRegex = stopwords.stream()
      .collect(Collectors.joining("|", "\\b(", ")\\b\\s?"));

    String result = original.toLowerCase().replaceAll(stopwordsRegex, "");
    assertEquals(result, target);
}

OstopwordsRegex resultante terá o formato “\ b (he | she | the |…) \ b \ s?”. In this regex, “” refers to a word boundary, to avoid replacing “he” in “heat” for example, while “\s?” refers to zero or one space, to delete the extra space after replacing a stopword.

6. Comparação de desempenho

Agora, vamos ver qual método tem o melhor desempenho.

Primeiro,let’s set up our benchmark. Usaremos um arquivo de texto bastante grande como fonte de nossoString chamadoshakespeare-hamlet.txt:

@Setup
public void setup() throws IOException {
    data = new String(Files.readAllBytes(Paths.get("shakespeare-hamlet.txt")));
    data = data.toLowerCase();
    stopwords = Files.readAllLines(Paths.get("english_stopwords.txt"));
    stopwordsRegex = stopwords.stream().collect(Collectors.joining("|", "\\b(", ")\\b\\s?"));
}

Então teremos nossos métodos de benchmark, começando comremoveManually():

@Benchmark
public String removeManually() {
    String[] allWords = data.split(" ");
    StringBuilder builder = new StringBuilder();
    for(String word : allWords) {
        if(!stopwords.contains(word)) {
            builder.append(word);
            builder.append(' ');
        }
    }
    return builder.toString().trim();
}

Em seguida, temos o benchmarkremoveAll():

@Benchmark
public String removeAll() {
    ArrayList allWords =
      Stream.of(data.split(" "))
            .collect(Collectors.toCollection(ArrayList::new));
    allWords.removeAll(stopwords);
    return allWords.stream().collect(Collectors.joining(" "));
}

Por fim, adicionaremos o benchmark parareplaceRegex():

@Benchmark
public String replaceRegex() {
    return data.replaceAll(stopwordsRegex, "");
}

E aqui está o resultado do nosso benchmark:

Benchmark                           Mode  Cnt   Score    Error  Units
removeAll                           avgt   60   7.782 ±  0.076  ms/op
removeManually                      avgt   60   8.186 ±  0.348  ms/op
replaceRegex                        avgt   60  42.035 ±  1.098  ms/op

Pareceusing Collection.removeAll() has the fastest execution time while using regular expressions is the slowest.

7. Conclusão

Neste artigo rápido, aprendemos diferentes métodos para remover palavras irrelevantes deString em Java. Também os comparamos para ver qual método tem o melhor desempenho.

O código-fonte completo dos exemplos está disponívelover on GitHub.