Манипуляции со строками в R: удаление указанного шаблона c в нескольких местах без удаления текста между экземплярами шаблона - PullRequest
3 голосов
/ 18 июня 2020

В R я пытаюсь написать код, который будет работать с любыми адаптациями строкового шаблона. Пример строки:

string <- "y ~ 1 + a + (b | c) + (d^2) + e + (1 | f) + g"

Я хотел бы удалить ТОЛЬКО те части, которые содержат шаблон «(, |,)», например:

(b | c) и (1 | f)

и оставить с:

"y ~ 1 + a + (d^2) + e + g"

Обратите внимание, что символы могут изменять значения (например, 'b' может становиться '1' и 'c 'может стать' предсказателем '), и я бы хотел, чтобы код по-прежнему работал. Пробелы также не требуются для строки, это также может быть «y ~ 1 + a + (b | c) + (d ^ 2) + e + (1 | f) + g» или любая комбинация пробела / no- пространство оного. Порядок символов также может измениться на «y ~ 1 + a + (b | c) + e + (1 | f) + (d ^ 2) + g».

Я пробовал использование базовых функций обработки строк R (gsub и sub) для поиска шаблона "(, |,)" с использованием вариантов шаблона, таких как:

"\\(.*\\|.*\\)"
"\\(.*\\|"
"\\(.+\\|.+\\)"
"\\|.+\\)"

, а также многих функций stringr найти и заменить этот узор на пробел. Однако, когда я использую как базовый R, так и stringr, когда я это делаю, он удаляет ВСЕ, например:

gsub("\\(.*\\|.*\\)", "", string)

дает:

"y ~ 1 + a +  + g"

и

gsub("\\(.*\\|", "", string)

производит:

"y ~ 1 + a +  f) + g"

Я дополнительно пробовал использовать функции str_locate, но у меня возникли проблемы с их эффективным использованием, так как существует несколько наборов круглых скобок, и мне нужны только местоположения экземпляров с "| " между ними.

Любая помощь приветствуется.

Ответы [ 3 ]

7 голосов
/ 18 июня 2020

1) gsubfn Определите функцию, которая возвращает пустую строку или ее ввод в зависимости от того, есть ли на входе | или нет и запустить с ним gsubfn. gsubfn похож на gsub, за исключением того, что строка замены может быть функцией, которая принимает совпадение как ввод и заменяет его выводом функции.

library(gsubfn)

pick <- function(x) if (grepl("|", x, fixed = TRUE)) "" else trimws(x)
gsubfn("[+] *[(].*?[)]", pick, string, perl = TRUE)
## [1] "y ~ 1 + a  + (d^2) + e  + g"

2) Base R Разделение ввода в термины и найдите без |. Затем соедините то, что осталось, используя reformulate.

s <- trimws(grep("\\|", strsplit(string, "[~+]")[[1]], invert = TRUE, value = TRUE))
reformulate(format(s[-1]), s[1])
## y ~ 1 + a + (d^2) + e + g

3) getTerms Это также использует только базовый R, но сначала преобразует строку в выражение, представляющее формулу, и анализирует его с использованием getTerms, найденного в этом сообщении SO: Термины суммы в выражении R Затем выполняется как в (2).

p <- parse(text = string)[[1]]
s <- grep("\\|", getTerms(p[[3]]), value = TRUE, invert = TRUE)
reformulate(s, p[[2]])
## y ~ 1 + a + (d^2) + e + g
1 голос
/ 18 июня 2020

Используя gsub мы можем добиться желаемых результатов.

model_texts <- c("y ~ 1 + a + (b | c) + (d^2) + e + (1 | f) + g",
"y~1+a+(b|c)+(d^2)+e+(1|f)+g" ,                 
"y~1+a+(b|c)+e+(1|f)+(d^2)+g" )   

pattern <- "\\(\\w ?\\| ?\\w ?\\) ?\\+ ?"

# tests

vapply(model_texts, function(x) gsub(pattern, "", x), "")

    "y ~ 1 + a + (d^2) + e + g" 
    "y~1+a+(d^2)+e+g" 
    "y~1+a+e+(d^2)+g" 



0 голосов
/ 18 июня 2020

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

"^\\([^|)]+\\|[^)]+\\) *\\+ ?| \\+? *\\([^|)]+\\|[^)]+\\)"

Запустите свой R-движок!

Это регулярное выражение простой в том смысле, что он не содержит поисковых запросов или более сложных функций регулярных выражений, поэтому не требует perl=TRUE. Это приводит к тому, что строка:

(h|i) + y ~ 1 + a + (b | c) + (d^2) + e + (1 | f) + g +(j+k| m)

становится 1 :

y ~ 1 + a  + (d^2) + e  + g

Первая часть чередования,

^\\([^|)]+\\|[^)]+\\) *\\+ ?

- это необходимо в случае, если (..|..) начинает строку (как и (h|i) в моем примере), и в этом случае перед ней не стоит знак плюс.

Следующая ссылка на regex101.com использует эквивалентное регулярное выражение для двигатель PCRE (PHP). Я включил это, чтобы позволить читателю изучить, как работает каждая часть регулярного выражения. (Переместите курсор, чтобы увидеть, как на экране волшебным образом всплывают интересные детали.)

Запустите двигатель PCRE!

1. Обратите внимание, что после 'a' и 'e' есть дополнительный пробел. Я предположил, что это не проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...