评估以字符串形式给出的表达式

Fed*_*rgi 263 eval r r-faq

我很想知道R是否可以使用它的eval()功能来执行例如字符串提供的计算.

这是一个常见的情况:

eval("5+5")
Run Code Online (Sandbox Code Playgroud)

但是,而不是10我得到:

[1] "5+5"
Run Code Online (Sandbox Code Playgroud)

有解决方案吗

Har*_*lan 392

eval()函数计算表达式,但它"5+5"是一个字符串,而不是表达式.使用parse()带有text=<string>字符串变成一个表达式:

> eval(parse(text="5+5"))
[1] 10
> class("5+5")
[1] "character"
> class(parse(text="5+5"))
[1] "expression"
Run Code Online (Sandbox Code Playgroud)

调用会eval()调用许多行为,有些行为不是很明显:

> class(eval(parse(text="5+5")))
[1] "numeric"
> class(eval(parse(text="gray")))
[1] "function"
> class(eval(parse(text="blue")))
Error in eval(expr, envir, enclos) : object 'blue' not found
Run Code Online (Sandbox Code Playgroud)

另请参见tryCatch.

  • 正如Shane在下面所说,"你需要指定输入是文本,因为默认情况下parse需要一个文件" (23认同)
  • @NelsonGon:使用“rlang”,您可以直接使用表达式,而不是字符串。无需解析步骤。它有两个优点。1. 表达式操作总是会产生有效的表达式。字符串操作只会产生有效的字符串。在解析它们之前,您不会知道它们是否是有效的表达式。2. 在字符串世界中没有与“substitute()”类函数等效的函数,这严重限制了您操作函数调用的能力。考虑[这个 glm 包装器](/sf/answers/4026976061/)。等效的字符串是什么样的? (2认同)

Sha*_*ane 93

您可以使用该parse()函数将字符转换为表达式.您需要指定输入是文本,因为默认情况下parse需要一个文件:

eval(parse(text="5+5"))
Run Code Online (Sandbox Code Playgroud)

  • @MartinMächler这很具有讽刺意味,因为核心R软件包始终使用`parse`!https://github.com/wch/r-source/search?utf8=%E2%9C%93&q=extension%3AR+parse&type= (9认同)
  • > fortune :: fortune("答案是解析")如果答案是解析(),你通常应该重新考虑这个问题. - Thomas Lumley R-help(2005年2月)> (7认同)

Mar*_*ler 46

抱歉,但我不明白为什么有太多人甚至认为字符串是可以评估的东西.你必须改变你的心态.忘记一边的字符串和表达式,调用,另一边的评估之间的所有连接.

(可能)唯一的连接是通过,parse(text = ....)并且所有优秀的R程序员应该知道这很少是构造表达式(或调用)的有效或安全的方法.而是要了解更多关于substitute(),quote()以及可能的使用的力量do.call(substitute, ......).

fortunes::fortune("answer is parse")
# If the answer is parse() you should usually rethink the question.
#    -- Thomas Lumley
#       R-help (February 2005)
Run Code Online (Sandbox Code Playgroud)

Dec.2017:好的,这是一个例子(在评论中,没有很好的格式):

q5 <- quote(5+5)
str(q5)
# language 5 + 5

e5 <- expression(5+5)
str(e5)
# expression(5 + 5)
Run Code Online (Sandbox Code Playgroud)

如果你获得更多的经验,会发现q5是一个"call",而e5"expression",甚至认为e5[[1]]是相同的q5:

identical(q5, e5[[1]])
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)

  • 你举个例子吗?也许你可以告诉我们如何在r对象中"保持"到5 + 5,然后使用引号和替换而不是字符和eval(parse(text =))来评估它? (3认同)
  • 我可能有点失落.你什么时候得到10?或者这不是重点? (3认同)
  • `eval(quote("5+10*2"))` 返回 `"5+10*2"` 而 `eval(parse(text="5+10*2"))` 返回 `25`。在这种情况下,“quote”似乎不是在这里使用的更好的函数...... (3认同)
  • `eval(quote())` 在某些情况下确实有效,但在某些情况下 `eval(parse())` 可以正常工作,但会失败。 (2认同)

dar*_*zig 18

或者,您可以evals从我的pander包中使用捕获输出和所有警告,错误和其他消息以及原始结果:

> pander::evals("5+5")
[[1]]
$src
[1] "5 + 5"

$result
[1] 10

$output
[1] "[1] 10"

$type
[1] "numeric"

$msg
$msg$messages
NULL

$msg$warnings
NULL

$msg$errors
NULL


$stdout
NULL

attr(,"class")
[1] "evals"
Run Code Online (Sandbox Code Playgroud)

  • 不错的功能;通过实际返回结果对象来填补由 `evaluate::evaluate` 留下的空洞;这使您的函数适合用于通过 mclapply 调用。我希望这个功能仍然存在! (2认同)

Paw*_*zko 13

现在你也可以使用包中的lazy_eval功能lazyeval.

> lazyeval::lazy_eval("5+5")
[1] 10
Run Code Online (Sandbox Code Playgroud)


小智 11

类似地使用rlang

eval(parse_expr("5+5"))
Run Code Online (Sandbox Code Playgroud)

  • 不仅有这些负面影响,它的名称也具有误导性。它不评估表达式。应该称为 parse_to_expr 或其他名称,以表明用户将知道它用于字符参数。 (6认同)
  • 来到这里寻找“rlang”答案,但是如果有的话,这个相对于基本替代方案的优势是什么?实际上,仔细检查所使用的代码表明它实际上使用了我想避免的“eval(parse(....))”。 (4认同)

Dav*_*sak 7

不知道为什么没有人专门提到两个 Base R 函数来执行此操作: str2lang()str2expression(). 这些是 的变体parse(),但似乎更干净地返回表达式:

eval(str2lang("5+5"))

# > 10
  
eval(str2expression("5+5"))

# > 10

Run Code Online (Sandbox Code Playgroud)

还想反击海报说任何试图这样做的人都是错误的。我正在阅读以文本形式存储在文件中的 R 表达式并尝试评估它们。这些功能非常适合此用例。

  • 这并不是说它“总是”错误,只是在很多很多情况下,以不同的方式做事会更安全、更好。 (3认同)