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() { ArrayListallWords = 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() { ArrayListallWords = 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 .