使用`deparse(substitute))`(或替代方法)时,如何处理空格?

时间:2019-03-14 16:28:01

标签: 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))))))
  

解析错误(文本= gsub(“”,“ _”,gsub(“ \”“,”“,gsub(” LN“,” log“,   ::1:9:意外输入1:log(x_a)_               ^

原因是deparse(substitute(LN("x a")*2^y))*周围引入了空格,然后我gsub在这些带有下划线的空格中出现了parse


有没有办法解决这个问题? 也许可以替代deparse(substitute))

(要指出一个明显的事实:用gsub(" ", "_", x)代替gsub(" ", "", x)并不是真正的选择,因为变量名变得不可读。例如,Reason one of Something将变成ReasononeofSomething,比尝试的Reason_one_of_Something可读性差。)

2 个答案:

答案 0 :(得分:6)

这是一个辅助函数,用于将表达式中的任何字符值替换为符号(用下划线替换空格)

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)

答案 1 :(得分:2)

如果输入是R调用对象,则它当然必须符合R语法。在那种情况下,我们可以使用递归函数来处理它,该递归函数遍历输入并替换包含一个或多个具有相同名称但使用下划线而不是空格的空格的名称。此外,最后用日志替换LN。返回调用对象。

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)