首页 > 解决方案 > R - 从字符串创建函数

问题描述

我在 Advanced R 的 Expressions 章节的 Parlist 部分遇到了以下函数:

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'),但这会返回 a而expression不是 a :callquote(a + b)

class(quote(a + b))
[1] "call"
class(parse(text = 'x^m'))
[1] "expression"

有没有办法call从字符串构造对象?

标签: rexpression

解决方案


您通常应该避免解析来自用户的任意字符串输入。通常,这可以通过适当的软件设计来避免。

无论如何,只需从表达式中提取语言:

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

在公共闪亮应用程序中解析和评估任意代码是一种安全风险。此检查确保只能使用一组预定义的函数。如果您不回避较小的风险,则可以使用黑名单代替(禁止使用system,system2等功能shell)。


推荐阅读