Наложение вхождений в RegEx Java

Необходимо найти все позиции вхождений в строке через регулярное выражение.

Пример:

Строка: cgcgcgcgcgcg

Вхождение: cgcg

Использую:

Pattern pattern = Pattern.compile("cgcg");
Matcher matcher = pattern.matcher("cgcgcgcgcgcg");
while (matcher.find())
    System.out.println(matcher.start());

Результат:

0
4
8

А ожидаю получить:

0
2
4
6
8

Как учесть все вхождения, включая те, которые будут накладываться?

UPD. Получилось сделать так, но есть ли более адекватный способ?

Pattern pattern = Pattern.compile("cgcg");
Matcher matcher = pattern.matcher("cgcgcgcgcgcg");
int start = 0;
while (matcher.find(start)) {
    start = matcher.start() + 1;
    System.out.println(matcher.start());
}

Ответы (1 шт):

Автор решения: Wiktor Stribiżew

Вам нужно найти все пересекающиеся совпадения с различными начальными позициями в строке. Это можно сделать с помощью регулярного выражения. Для этого вам понадобится позитивный блок предварительного просмотра вперёд и захватывающая подмаска:

String regex = "cgcg";
Pattern pattern = Pattern.compile("(?=(" + regex + "))");
// Если regex не шаблон, а простой текст, экранируйте его перед использованием в REGEX
// Pattern pattern = Pattern.compile("(?=(" + Pattern.quote(regex) + "))");
Matcher matcher = pattern.matcher("cgcgcgcgcgcg");
while (matcher.find())
    System.out.println(matcher.start(1));

С использованием streams:

List<Integer> results = pattern.matcher("cgcgcgcgcgcg")
        .results()
        .map(r -> r.start(1))
        .collect(Collectors.toList());

См. пример кода в Java

Результат:

0
2
4
6
8

и

[0, 2, 4, 6, 8]
→ Ссылка