我在 Parlist section of the Expressions chapter in Advanced R 中遇到了下面的函数:
make_function <- function(args, body, env = parent.frame()) {
args <- as.pairlist(args)
eval(call("function", args, body), env)
}
该函数允许用户从其组成部分构造函数:形式参数列表、函数体和环境。例如
add <- make_function(alist(a = 1, b = 2), quote(a + b))
add
function (a = 1, b = 2)
a + b
class(add)
[1] "function"
我想知道是否可以修改该函数以允许用户为 body
参数输入字符串?我尝试过 parse(text = 'a + b')
但这会返回一个表达式
,而不是 quote(a + b)
中的调用
:
class(quote(a + b))
[1] "call"
class(parse(text = 'x^m'))
[1] "expression"
有没有办法从字符串构造一个call
对象?
最佳答案
您通常应该避免解析用户输入的任意字符串。通常,可以通过适当的软件设计来避免这种情况。
无论如何,只需从表达式中提取语言即可:
make_function(alist(a = 1, b = 2), parse(text = 'a^b')[[1]])
编辑:
只是为了展示如何检查白名单(不涉及正则表达式):
whitelist <- c("+", "*", "-", "/", "^", "**", "%%", "%/%", "sin", "cos", "tan", "abs") #etc.
expr <- parse(text = "cos(x)^sin(x)*abs(x)")
foo <- function(e) if (length(e) > 1) lapply(as.list(e), foo) else return(e)
funs <- unlist(foo(expr[[1]]))
funs <- funs[vapply(funs, function(x) {x <- eval(x); is.function(x) | is.primitive(x)}, FUN.VALUE = TRUE)]
all(vapply(funs, function(x) as.character(x) %in% whitelist, FUN.VALUE = TRUE))
在公共(public) Shiny 应用程序中解析和评估任意代码存在安全风险。此检查确保只能使用一组预定义的函数。如果您不回避较小的风险,您可以使用黑名单来代替(禁止诸如 system
、system2
、shell
等功能。 )。
关于R - 从字符串创建函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58389523/