Перекрывающиеся совпадения в R
Я искал и смог найти это обсуждение форума для достижения эффекта совпадающих совпадений.
Я также нашел следующий qaru.site/info/382061/... вопрос о поиске индексов для выполнения этой задачи, но не смог найти что-либо краткое о захвате совпадающих совпадений на языке R.
Я могу выполнить эту задачу на большинстве языков, поддерживающих (PCRE) с помощью утверждения Positive Lookahead при реализации группы захвата внутри просмотра для захвата совпадающих совпадений.
Но, фактически выполняя это так же, как и на других языках, используя perl=T
в R, результаты не получаются.
> x <- 'ACCACCACCAC'
> regmatches(x, gregexpr('(?=([AC]C))', x, perl=T))[[1]]
[1] "" "" "" "" "" "" ""
То же самое касается использования пакетов stringi
и stringr
.
> library(stringi)
> library(stringr)
> stri_extract_all_regex(x, '(?=([AC]C))')[[1]]
[1] "" "" "" "" "" "" ""
> str_extract_all(x, perl('(?=([AC]C))'))[[1]]
[1] "" "" "" "" "" "" ""
Правильные результаты, которые должны быть возвращены при выполнении этого:
[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
Изменить
-
Мне хорошо известно, что regmatches
плохо работает с захваченными совпадениями, но что точно вызывает это поведение в регматиках и почему результаты не возвращаются? Я убираю несколько подробный ответ.
-
Является ли пакет stringi
и stringr
не способен выполнять это через regmatches
?
-
Пожалуйста, не стесняйтесь добавлять к моему ответу или придумывать другое обходное решение, чем я нашел.
Ответы
Ответ 1
Стандартная regmatches
не работает с захваченными совпадениями (в частности, несколько захваченных совпадений в одной строке). И в этом случае, поскольку вы "сопоставляете" взгляд вперед (игнорируя захват), само совпадение имеет нулевую длину. Существует также функция regmatches()<-
, которая может это проиллюстрировать. Obseerve
x <- 'ACCACCACCAC'
m <- gregexpr('(?=([AC]C))', x, perl=T)
regmatches(x, m) <- "~"
x
# [1] "~A~CC~A~CC~A~CC~AC"
Обратите внимание, что все буквы сохранены, мы только что заменили места совпадений нулевой длины тем, что мы можем наблюдать.
Я создал функцию regcapturedmatches(), которую я часто использую для таких задач. Например
x <- 'ACCACCACCAC'
regcapturedmatches(x, gregexpr('(?=([AC]C))', x, perl=T))[[1]]
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
gregexpr
полностью захватывает все данные, поэтому вы можете извлечь его из этого объекта в любом случае, если вы предпочитаете не использовать эту вспомогательную функцию.
Ответ 2
Что касается обходного пути, это то, что я придумал, чтобы извлечь совпадающие совпадения.
> x <- 'ACCACCACCAC'
> m <- gregexpr('(?=([AC]C))', x, perl=T)
> mapply(function(X) substr(x, X, X+1), m[[1]])
[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
Не стесняйтесь добавлять или комментировать лучший способ выполнить эту задачу.
Ответ 3
Другим способом обхода одной и той же информации, которую я делал в прошлом, является замена "match.length"
на "capture.length"
:
x <- c("ACCACCACCAC","ACCACCACCAC")
m <- gregexpr('(?=([AC]C))', x, perl=TRUE)
m <- lapply(m, function(i) {
attr(i,"match.length") <- attr(i,"capture.length")
i
})
regmatches(x,m)
#[[1]]
#[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
#
#[[2]]
#[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
Ответ 4
Это не решение регулярных выражений и на самом деле не отвечает на ваши более важные вопросы, но вы также можете получить желаемый результат, используя подстроки из двух символов за раз, а затем удаляя ненужные элементы CA
.
x <- 'ACCACCACCAC'
y <- substring(x, 1:(nchar(x)-1), 2:nchar(x))
y[y != "CA"]
# [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
Ответ 5
A stringi
с использованием группы захвата в передней части:
> stri_match_all_regex('ACCACCACCAC', '(?=([AC]C))')[[1]][,2]
## [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
Это не работает с stringr
, поскольку str_match_all
не поддерживает регулярные выражения PCRE.
Ответ 6
Дополнительный ответ, основанный на собственном ответе @hwnd (оригинал не разрешил захваченные области с переменной длиной), используя только встроенные функции R:
> x <- 'ACCACCACCAC'
> m <- gregexpr('(?=([AC]C))', x, perl=T)[[1]]
> start <- attr(m,"capture.start")
> end <- attr(m,"capture.start") + attr(m,"capture.length") - 1
> sapply(seq_along(m), function(i) substr(x, start[i], end[i]))
[1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"
Довольно уродливый, поэтому существуют пакеты stringr
и т.д.