#r
#r
Вопрос:
Я пишу некоторый код, который переводит определения математических функций в допустимый R-код. Поэтому я использую deparse(substitute))
для доступа к этим определениям функций, чтобы я мог изменить их на действительный R-код.
Например, у меня есть функция, LN(x)^y
которая должна стать log(x)^y
. Я могу сделать это, используя первую версию моей to_r
функции:
to_r <- function(x) {
parse(text = gsub("LN", "log", deparse(substitute(x))))
}
to_r(LN(x)^y)
Это возвращает expression(log(x)^y)
то, что я ожидаю.
Я также получаю определения функций, выглядящие как LN("x a")^y
. Чтобы обрабатывать их, я могу расширить свою функцию:
to_r_2 <- function(x) {
parse(text = gsub(" ", "_", gsub(""", "", gsub("LN", "log", deparse(substitute(x))))))
}
to_r_2(LN("x a")^y)
Это возвращает expression(log(x_a)^y)
, что нормально.
Однако, когда мой ввод становится чем-то вроде LN("x a")*2^y
этого, происходит сбой:
parse(text = gsub(" ", "_", gsub(""", "", gsub("LN", "log", deparse(substitute(LN("x a")*2^y))))))
Ошибка при синтаксическом анализе (text = gsub(«», «_», gsub(«»», «»», gsub («LN», «log»,
: :1:9: неожиданный ввод 1: log (x_a)_
^
Причина в том, что deparse(substitute(LN("x a")*2^y))
вводятся пробелы вокруг *
, а затем I gsub
эти пробелы с подчеркиванием, что является проблемой для parse
.
Есть ли способ решить эту проблему? Может быть, альтернатива deparse(substitute))
?
(Констатируя очевидное: замена gsub(" ", "_", x)
на gsub(" ", "", x)
на самом деле не вариант, потому что имена переменных становятся нечитаемыми. Например, Reason one of Something
стало бы ReasononeofSomething
гораздо менее читаемым, чем предпринятое Reason_one_of_Something
.)
Комментарии:
1. Я здесь немного запутался. Можете ли вы четко определить, что такое необработанный ввод (строка? выражение, заключенное в кавычки? обещание?) и каков желаемый результат для этого ввода. Возможно, разделите ваш код на функцию, чтобы мы могли четко видеть, какие части мы можем изменить. Я не уверен точно, каковы ваши правила для синтаксического анализа недопустимых операторов.
2. @MrFlick: Идея состоит в том, чтобы поместить это внутри функции, чтобы иметь вызовы типа:
to_r(LN(x)^y)
, смотрите Мою правку.3. Но вы никогда не сможете вызвать
to_r_2(LN(x a)^y)
. Если вы передаете выражение, оно должно использовать допустимый синтаксис R. Откуда вы знаете, действительно ли они пытаются передать строку в вашу функцию? Вы хотите заменить каждую строку символом?4. @MrFlick: Вы правы.
to_r_2(LN(x a)^y
никогда не будет работать. Я удалил этот регистр. Есть ли еще способ обработатьto_r_2(LN("x a")*2^y
случай?5. Я думал, что gsub был бы идеальным вариантом использования для
rapply
но, к сожалению, он не обрабатывает вызовы как списки… Хотя это было бы неплохо…rapply(x,function(x) as.symbol(gsub(" ","_",x)), "character", how = "replace")
Ответ №1:
Вот вспомогательная функция для замены любых символьных значений в выражении символами (с заменой пробелов символами подчеркивания)
chr_to_sym <- function(x) {
if (is(x, "call")) {
as.call(do.call("c",lapply(as.list(x), chr_to_sym), quote=T))
} else if (is(x, "character")) {
as.symbol(gsub(" ","_", x))
} else {
x
}
}
Затем мы можем использовать это в вашей функции перевода
to_r <- function(x) {
expr <- substitute(x)
expr <- do.call("substitute", list(expr, list(LN=quote(log))))
as.expression(chr_to_sym(expr))
}
обратите внимание, что эта версия работает с выражениями напрямую. Он не выполняет никаких операций с удалением / строкой. Это, как правило, безопаснее. Это работает для примеров, которые вы предоставляете
to_r(LN(x)^y)
# expression(log(x)^y)
to_r(LN("x a")^y)
# expression(log(x_a)^y)
to_r(LN("x a")*2^y)
# expression(log(x_a) * 2^y)
Ответ №2:
Если ввод является объектом вызова R, то он, конечно, должен соответствовать синтаксису R. В этом случае мы можем обработать это с помощью рекурсивной функции, которая просматривает входные данные и заменяет имена, содержащие пробел или пробелы, на те же имена, но с подчеркиванием вместо пробелов. Кроме того, в конце заменяет LN на log . Возвращается объект вызова.
rmSpace <- function(e) {
if (length(e) == 1) e <- as.name(gsub(" ", "_", as.character(e)))
else for (i in 1:length(e)) e[[i]] <- Recall(e[[i]])
do.call("substitute", list(e, list(LN = as.name("log"))))
}
rmSpace(quote(LN("x a")*2^y))
## log(x_a) * `2`^y
# to input an expression add [[1]] after it to make it a call object
rmSpace(expression(LN("x a")*2^y)[[1]])
## log(x_a) * `2`^y
Примените as.expression к результату, если вы хотите выражение вместо объекта вызова.
Если входные данные представляют собой символьную строку, то мы можем просто заменить LN
на log
, а для любого пробела, имеющего цифру или букву с обеих сторон, мы можем заменить пробелы символом подчеркивания. Мы возвращаем строку или вызываемый объект в зависимости от второго аргумента.
rmSpace2 <- function(s, retclass = c("character", "call")) {
s1 <- gsub("\bLN\b", "log", s)
s2 <- gsub("([[:alnum:]]) ([[:alnum:]])", "\1_\2", s1, perl = TRUE)
retclass <- match.arg(retclass)
if (retclass == "character") s2 else parse(text = s2)[[1]]
}
rmSpace2("LN(x a)*2^y")
## [1] "log(x_a)*2^y"
rmSpace2("LN(x a)*2^y", "call")
## log(x_a) * 2^y
Если вам нужно выражение вместо объекта вызова, используйте as.expression
:
as.expression(rmSpace2("LN(x a)*2^y", "call"))
## expression(log(x_a) * 2^y)