Перекрывающиеся спички в R

Я искал и смог найти это обсуждение на форуме для достижения эффекта совпадения совпадений.

Я также нашел следующий вопрос SO, говорящий о поиске индексов для выполнения этой задачи, но не смог найти ничего краткого о получении перекрывающихся совпадений в языке R.

Я могу выполнить эту задачу практически на любом языке, который поддерживает ( PCRE), используя утверждение Positive Lookahead при реализации группы захвата внутри 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"

редактировать

  1. Я хорошо знаю, что regmatches плохо работает с захваченными совпадениями, но что именно вызывает такое поведение в матчах и почему не возвращаются результаты? Я собираюсь получить несколько подробный ответ.

  2. Это stringi а также stringr пакет не способен выполнить это более regmatches?

  3. Пожалуйста, не стесняйтесь добавлять к моему ответу или придумать другой обходной путь, чем я нашел.

6 ответов

Решение

Стандарт 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 просто отлично захватывает все данные, так что вы можете извлечь их из этого объекта в любом случае, если вы предпочитаете не использовать эту вспомогательную функцию.

Что касается обходного пути, это то, что я придумал, чтобы извлечь перекрывающиеся совпадения.

> 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"

Пожалуйста, не стесняйтесь добавлять или комментировать лучший способ выполнить эту задачу.

stringi Решение с использованием группы захвата в прогнозной части:

> stri_match_all_regex('ACCACCACCAC', '(?=([AC]C))')[[1]][,2]
## [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"    

Это не работает с stringr как str_match_all не поддерживает регулярные выражения PCRE.

Это не решение регулярных выражений, и оно не отвечает на любые ваши более важные вопросы, но вы также можете получить желаемый результат, используя подстроки из двух символов одновременно, а затем удаляя ненужные CA элементы.

x <- 'ACCACCACCAC'
y <- substring(x, 1:(nchar(x)-1), 2:nchar(x))
y[y != "CA"]
# [1] "AC" "CC" "AC" "CC" "AC" "CC" "AC"

Еще один окольный способ извлечения той же информации, которую я делал в прошлом, - это заменить "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"

Дополнительный ответ, основанный на собственном ответе @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 и т.д. пакеты существуют.

Другие вопросы по тегам