Для поиска подходящих слов можно разбить строку на слова при помощи String::split
, а затем отфильтровать слова при помощи String::matches
с соответствующим регулярным выражением. Также можно искать слова при помощи заранее подготовленного шаблона для поиска трёх букв подряд и метода Matcher::find
. Или же можно сразу искать подходящие слова в строке без String::split при помощи соответствующего шаблона.
При использовании Stream API есть способы получить список без дубликатов:
Stream::distinct
Самый простой способ, но при нём слова разного регистра будут считаться разными
- Собрать результат в сет, который затем скопируется в список
Чтобы считать слова разного регистра одинаковыми (например, Aaa
/ AAA
/ aaa
), можно собирать результат в TreeSet
с компаратором String::CASE_INSENSITIVE_ORDER
, при этом порядок вхождения слов в начальную строку будет нарушен, так как такой сет будет отсортирован по алфавиту
- Собрать результат в мапу с одним значением (первым или последним вхождением) и добавить коллекцию значений в список
Этот способ позволит сохранить порядок вхождения слов в начальной строке, игнорируя дубликаты в разном регистре
Пример решения: Pattern + Matcher.find + Collectors.toMap
static final Pattern THREE_LETTERS = Pattern.compile("([a-zа-яё])\\1{2}", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
public static List<String> withTriplets(String str) {
return new ArrayList<>(Arrays
.stream(str.split("[^a-zA-Zа-яА-ЯёЁ0-9]+"))
//.filter(w -> w.matches("(?iu).*([a-zа-яё])\\1{2}.*"))
.filter(w -> THREE_LETTERS.matcher(w).find())
.collect(Collectors.toMap(
String::toLowerCase, w -> w, (a, b) -> a, LinkedHashMap::new
))
.values()
);
}
Тест:
System.out.println(withTriplets("Бешеный зооОхранитель Пресссельхоза расстрелял длинношеее чудовище и скормил останки ручному змееЕду. Длинношеее блюдо понравилось змеееду."));
[зооОхранитель, Пресссельхоза, длинношеее, змееЕду]