Замена нескольких шаблонов управляемым шаблоном

У меня есть текстовая строка, которую я хотел бы преобразовать из

text = "end back@drive@o correct back@drive@adjust@cats@do to tok"

to

"end back@drive drive@o correct back@drive drive@adjust adjust@cats cats@do to tok"

Скорее вообще хочу заменить

"a@b@c" with "a@b b@c"
"a@b@c@d" with "a@b b@c c@d"

и так далее. В моей попытке ниже используется пакет stringr.

patterns = unlist(str_extract_all(text, "([[:alnum:]]+@){2,}[[:alnum:]]+"))
replacements = strsplit(patterns, "@")
replacements = lapply(replacements, function(y) {
  pretuples = y[-length(y)]  
  posttuples = y[-1]
  paste(paste0(pretuples, "@", posttuples), collapse = " ")
})  
replacements = do.call(c, replacements)
str_replace_all(text, pattern = patterns, replacement = replacements)

Я не думаю, что str_replace_all - это функция, которую я ищу в конце, и, конечно, она (разумно) возвращает

[1] "end back@drive drive@o correct back@drive@adjust to tok" 
[2] "end back@drive@o correct back@drive drive@adjust adjust@cats cats@do to tok"

Может ли кто-нибудь помочь мне разобраться в этом?

Спасибо большое.

РЕДАКТИРОВАТЬ: ответы до сих пор были невероятно полезными, но это большой файл, который я разбираю и действительно не знаю, сколько раз этот шаблон a@b@c@d... будет связан. Есть ли более общее решение, которое не полагается на жесткое кодирование длины шаблона (как я пробовал выше)?


person Akhil Nair    schedule 01.07.2015    source источник


Ответы (3)


Пытаться

pat <- "(\\s|\\b)[^@]+\\s(*SKIP)(*FAIL)|(?<=@)([^@]*)(?=@)"
repl <- "\\2 \\2"
gsub(pat, repl, text, perl=TRUE)
#[1] "end back@drive drive@o correct back@drive drive@adjust adjust@cats cats@do to tok"

Для "str1"

gsub(pat, repl, str1, perl=TRUE)
#[1] "a@b b@c"                     "a@b b@c c@d"                
#[3] "a@b b@c c@d d@e e@f f@g g@h"

данные

text  <- "end back@drive@o correct back@drive@adjust@cats@do to tok"
str1 <- c("a@b@c", "a@b@c@d", "a@b@c@d@e@f@g@h")
person akrun    schedule 01.07.2015

> gsub(x = text, pattern = '@(.*?)@', replacement = '@\\1 \\1@')
[1] "end back@drive drive@o correct back@drive drive@adjust to tok"

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

В ответ на комментарий - вам, вероятно, нужно запустить цепочку gsub(x = text, pattern = '@([[:alnum:]]{1,})@', replacement = '@\\1 \\1@') в тексте, пока он не изменится. Опять же, без дополнительных тестовых примеров нельзя быть уверенным.

person TheComeOnMan    schedule 01.07.2015
comment
Феноменальный. Есть ли способ зафиксировать это в общем случае для a@...@d? - person Akhil Nair; 01.07.2015
comment
Спасибо. Я немного изменил данный тестовый пример, чтобы включить более общий случай. Я использую пока цикл и приму его, если в ближайшее время никто не ответит с волшебным решением, которое я ищу. - person Akhil Nair; 01.07.2015

Я бы использовал gsub:

> text = "end back@drive@o correct back@drive@adjust to tok"
> gsub(pattern = "([[:alpha:]]+)@([[:alpha:]]+)@([[:alpha:]]+)", replacement = "\\1@\\2 \\2@\\3", x = text)
[1] "end back@drive drive@o correct back@drive drive@adjust to tok"
person PAC    schedule 01.07.2015