Рубрики
Без рубрики

Удаление стоп-слов из строки в Java

Посмотрите на способы удаления определенных слов из строки Java

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы обсудим различные способы удаления стоп-слов из строки | в Java. Это полезная операция в тех случаях, когда мы хотим удалить нежелательные или запрещенные слова из текста, такие как комментарии или отзывы, добавленные пользователями онлайн-сайта.

Мы будем использовать простой цикл Collection.removal() и регулярные выражения.

Наконец, мы сравним их производительность с помощью жгута Java Microbenchmark .

2. Загрузка Стоп-слов

Сначала мы загрузим наши стоп-слова из текстового файла.

Вот у нас есть файл english_stopwords.txt которые содержат список слов, которые мы рассматриваем как стоп-слова, такие как I , he , she и the .

Мы загрузим стоп-слова в Список из Строки с помощью Files.ReadAllLines() :

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

3. Удаление Стоп-Слов Вручную

Для нашего первого решения мы удалим стоп-слова вручную, повторяя каждое слово и проверяя, является ли оно стоп-словом :

@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. Использование Collection.removeAll()

Далее, вместо того, чтобы перебирать каждое слово в нашей Строке , мы можем использовать Collection.removeAll() для удаления всех стоп-слов сразу :

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

В этом примере после разделения нашей Строки на массив слов мы преобразуем ее в ArrayList , чтобы иметь возможность применить метод removeAll () .

5. Использование Регулярных Выражений

Наконец, мы можем создать регулярное выражение из нашего стоп-слов списка , а затем использовать его для замены стоп-слов в нашей строке :

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

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

Результирующее регулярное выражение стоп-слов будет иметь формат “\\b(он|она|/…)\\b\ \ s?”. В этом регулярном выражении “\b” относится к границе слова, чтобы избежать замены “he” в “heat”, например, в то время как “\s?” относится к нулю или одному пробелу, чтобы удалить лишний пробел после замены стоп-слова.

6. Сравнение производительности

Теперь давайте посмотрим, какой метод имеет лучшую производительность.

Во-первых, давайте установим наш бенчмарк . Мы будем использовать довольно большой текстовый файл в качестве источника нашей Строки под названием shakespeare-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?"));
}

Затем у нас будут наши методы тестирования, начиная с удалить вручную() :

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

Далее у нас есть удалить все() бенчмарк:

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

Наконец, мы добавим тест для replaceRegex() :

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

И вот результат нашего бенчмарка:

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

Похоже, что использование Collection.removeAll() имеет самое быстрое время выполнения, в то время как использование регулярных выражений является самым медленным .

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

В этой краткой статье мы изучили различные методы удаления стоп-слов из строки | в Java. Мы также провели сравнительный анализ, чтобы определить, какой метод имеет наилучшую производительность.

Полный исходный код примеров доступен на GitHub .