Перекрывающиеся совпадения в 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 и т.д.