评估作为字符串给出的表达式
Posted
技术标签:
【中文标题】评估作为字符串给出的表达式【英文标题】:Evaluate expression given as a string 【发布时间】:2010-12-17 03:41:08 【问题描述】:我很想知道 R 是否可以使用它的eval()
函数来执行由例如提供的计算。一个字符串。
这是一种常见的情况:
eval("5+5")
但是,我得到的不是 10:
[1] "5+5"
有什么办法吗?
【问题讨论】:
尽管所有答案都显示了如何使用 parse 解决这个问题......为什么需要将语言类型存储在字符string
中? Martin Mächler 的回答应该得到更多的支持。
谢谢@PetrMatousu。是的,我很震惊地看到错误信息现在是如何在 SO 上传播的……人们支持 eval(parse(text = *))
虚假解决方案。
我想运行以下形式的脚本:QQ = c('11','12','13','21','22','23')
,即:QQ =c(...,'ij',..) 其中 i,j 在可能不同的范围内变化从跑到跑。对于这个和类似的例子,我可以把脚本写成paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")
,选项eval(parse(text=...))
根据脚本在工作环境中创建向量QQ。如果不是使用“text=...”,那么正确的 R 编码器方法是什么?
【参考方案1】:
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"
调用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
另见tryCatch。
【讨论】:
正如 Shane 在下面指出的,“您需要指定输入是文本,因为 parse 默认需要一个文件” 应该指定使用 eval(parse) 的副作用。例如,如果您有一个预定义的变量 name 等于 "David",并且您使用 eval(parse(text = "name") == "Alexander" 重新分配,您将收到一个错误,因为eval & parse 不返回可以计算的 R 表达式。 @NelsonGon:使用quote()
、bquote()
或rlang
包提供的更复杂的工具构造的未计算表达式。
@ArtemSokolov 谢谢,我不知何故一直回到这个问题寻找替代方案。我看过rlang
,但我发现最接近的是parse_expr
,它调用parse_exprs
,这又与使用parse
并将其包装在eval
中相同,这似乎与此处所做的相同.我不确定使用rlang
有什么好处。
@NelsonGon:使用rlang
,您可以直接使用表达式,而不是字符串。无需解析步骤。它有两个优点。 1. 表达式操作总是会产生有效的表达式。字符串操作只会产生有效的字符串。在解析它们之前,您不会知道它们是否是有效的表达式。 2. 在字符串世界中没有等价于substitute()
类的函数,这严重限制了你操作函数调用的能力。考虑this glm wrapper。等价的字符串是什么样的?【参考方案2】:
您可以使用parse()
函数将字符转换为表达式。您需要指定输入是文本,因为 parse 默认需要一个文件:
eval(parse(text="5+5"))
【讨论】:
> fortunes::fortune("answer is parse") 如果答案是 parse() 你通常应该重新考虑这个问题。 -- Thomas Lumley R-help(2005 年 2 月)> @MartinMächler 这很讽刺,因为核心 R 包一直使用parse
! github.com/wch/r-source/…【参考方案3】:
抱歉,我不明白为什么有太多人甚至认为字符串是可以评估的。你必须改变你的心态,真的。 忘记一侧的字符串与另一侧的表达式、调用、评估之间的所有连接。
(可能)唯一的连接是通过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)
2017 年 12 月:好的,这是一个示例(在 cmets 中,没有很好的格式):
q5 <- quote(5+5)
str(q5)
# language 5 + 5
e5 <- expression(5+5)
str(e5)
# expression(5 + 5)
如果你有更多经验,你会发现q5
是"call"
而e5
是"expression"
,甚至e5[[1]]
与q5
相同:
identical(q5, e5[[1]])
# [1] TRUE
【讨论】:
你能举个例子吗?也许您可以向我们展示如何在 r 对象中“保持”到 5+5,然后使用引号和替换而不是字符和 eval(parse(text=)? 我可能有点失落。你什么时候得到10?或者这不是重点? @RichardDiSalvo:是的,上面的q5 <- quote(5+5)
是表达式(实际上是“调用”)5+5
,它是一个R对象,但不是字符串。您可以随时对其进行评估。再说一遍:使用,quote(),substitute(),... instead parse 直接创建调用或表达式,并且比 via parse(text= . ) 更有效。使用eval()
很好,使用parse(text=*)
容易出错,有时与构造调用和操作它们相比效率很低。@Nick S:在我们的运行示例中是eval(q5)
或eval(e5)
@NickS :要获得 10,请评估调用/表达式,即对其调用 eval(.)
。我的观点是人们不应该使用parse(text=.)
而应该使用quote(.)
等来构建稍后将是eval()
ed 的调用。
eval(quote())
在少数情况下确实有效,但在 eval(parse())
可以正常工作的某些情况下会失败。【参考方案4】:
或者,您可以使用我的pander
包中的evals
来捕获输出和所有警告、错误和其他消息以及原始结果:
> 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"
【讨论】:
不错的功能;通过实际返回结果对象来填充evaluate::evaluate
留下的漏洞;这使您的函数适合用于通过 mclapply 调用。我希望这个功能仍然存在!
谢谢你,@rpierce。这个函数最初是在 2011 年作为我们 rapport
包的一部分编写的,并且从那时起一直在积极维护,因为除了一些其他项目之外,我们的 rapporter.net 服务中也大量使用它——所以我相信它会保留维护了一段时间 :) 很高兴您发现它很有用,感谢您的友好反馈。【参考方案5】:
现在您还可以使用lazyeval
包中的lazy_eval
函数。
> lazyeval::lazy_eval("5+5")
[1] 10
【讨论】:
【参考方案6】:不知道为什么没有人专门提到两个 Base R 函数来执行此操作:str2lang()
和 str2expression()
。这些是parse()
的变体,但似乎更干净地返回表达式:
eval(str2lang("5+5"))
# > 10
eval(str2expression("5+5"))
# > 10
还想反击海报说任何试图这样做的人都是错误的。我正在读取存储为文件中文本的 R 表达式并尝试评估它们。这些函数非常适合这个用例。
【讨论】:
这并不是说它总是错,只是有很多很多情况下,以不同的方式做事会更安全、更好。【参考方案7】:同样使用rlang
:
eval(parse_expr("5+5"))
【讨论】:
来到这里寻找rlang
的答案,但如果有什么比基本替代品的优势呢?实际上,仔细检查所使用的代码表明它实际上是在使用eval(parse(....))
,这是我想避免的。
不仅是那些负面的,而且它的名字也具有误导性。它不评估表达式。应该称为 parse_to_expr 或其他名称,以表明用户将知道它打算用于字符参数。以上是关于评估作为字符串给出的表达式的主要内容,如果未能解决你的问题,请参考以下文章