РЕШЕНИЕ
Решение заключается в использовании двигателей регулярного выражения PCRE или ICU, а не TRE.
Используйте любую базу R gsub
с perl=TRUE
(используется шаблон PCRE regex ) и шаблон "(?s)(.{2,})\\1+"
или stringr::str_replace_all()
(используется ICU regex engine ) с тем же шаблоном:
> x <- "cdababcdcd"
> gsub("(?s)(.{2,})\\1+", "\\1", x, perl=TRUE)
[1] "cdabcd"
> library(stringr)
> str_replace_all(x, "(?s)(.{2,})\\1+", "\\1")
[1] "cdabcd"
Флаг (?s)
необходим, чтобы .
соответствовал любому символу, включая символы разрыва строки (в регулярном выражении TRE .
соответствует всем символам по умолчанию).
ДЕТАЛИ
Регулярное выражение TRE плохо справляется с "патологическими" случаями, которые в основном связаны с возвратом, который напрямую связан с квантификаторами (я выделил некоторые части):
СоответствиеАлгоритм, используемый в TRE, использует линейное время наихудшего случая по длине искомого текста и квадратичное время наихудшего случая по длине используемого регулярного выражения.Другими словами, временная сложность алгоритма составляет O (M2N) , где M - длина регулярного выражения, а N - длинаtext. Используемое пространство также квадратично по длине регулярного выражения, но не зависит от искомой строки.Это квадратичное поведение имеет место только в патологических случаях, которые, вероятно, очень редки на практике.
Предсказуемая скорость совпадения Из-за алгоритма сопоставления, используемого в TRE, максимальное время, затрачиваемое на любой вызов regexec()
, всегда прямо пропорционально длине искомой строки.Есть одно исключение: если используются обратные ссылки, сопоставление может занять время, которое растет экспоненциально с длиной строки. Это потому, что сопоставление обратных ссылок - это полная проблема NP , и почти навернякав наихудшем случае требуется экспоненциальное время для сопоставления.
В тех случаях, когда TRE не удается вычислить все возможности сопоставления строки, она не возвращает совпадения, строка возвращается как есть .Следовательно, в вызове gsub
нет никаких изменений.