文字列として与えられた式を評価する


283

Rがそのeval()関数を使用して、たとえば文字列によって提供される計算を実行できるかどうか知りたいです。

これは一般的なケースです。

eval("5+5")

しかし、10の代わりに私は得ます:

[1] "5+5"

解決策はありますか?


6
解析でそれを解決する方法を示すすべての回答にもかかわらず...なぜ言語タイプを文字に格納する必要があるのstringですか?マーティン・メヒラーの答えは、もっと多くの賛成票に値するはずです。
Petr Matousu

7
@PetrMatousuありがとうございます。はい、私は今、eval(parse(text = *)) 偽のソリューションを支持する人々によって誤った情報がSOに広まっているのを見てショックを受けています 。
MartinMächler2017

2
次の形式のスクリプトを実行したいと思います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コーダーの方法は何でしょうか?
VictorZurkowski、

回答:


418

eval()関数は、式を評価しますが、"5+5"文字列、ない表現です。文字列を式に変更するには、parse()with 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も参照してください。


27
Shaneが以下に記しているように、「解析ではデフォルトでファイルが予期されるため、入力がテキストであることを指定する必要があります」
PatrickT

1
eval(parse)を使用した場合の副作用を指定する必要があります。たとえば、"David"と等しい定義済みの変数があり、eval(parse(text = "name")== "Alexander"を使用して再割り当てした場合、eval&parseはエラーを返さないため、エラーが発生します。評価可能なR式
Crt

1
@NelsonGon:未評価の表現は使用して構築quote()bquote()またはによって提供されるより洗練されたツールrlangのパッケージ。
Artem Sokolov

@ArtemSokolovありがとう、私はどういうわけか、代替案を探してこの質問に戻ってきます。私は見ましたrlangが、私が見つけた最も近いものはparse_expr、呼び出しparse_exprsを使用parseしてラップevalすることと同じであり、ここで行ったのと同じように見えることです。を使用する利点が何であるかわかりませんrlang
NelsonGon

1
@NelsonGon:ではrlang、文字列ではなく式を直接操作します。解析手順は必要ありません。これには2つの利点があります。1.式を操作すると、常に有効な式が生成されます。文字列操作では、有効な文字列のみが生成されます。それらが解析されるまで、それらが有効な式であるかどうかはわかりません。2. substitute()文字列の世界には、関数呼び出しを操作する機能を大幅に制限する関数のクラスに相当するものはありません。このglmラッパーを検討してください。同等の文字列はどのようになりますか?
Artem Sokolov

100

parse()関数を使用して、文字を式に変換できます。parseはデフォルトでファイルを想定しているため、入力がテキストであることを指定する必要があります。

eval(parse(text="5+5"))

7
> fortunes :: fortune( "answer is parse")答えがparse()の場合、通常は質問を再考する必要があります。
-Thomas

13
@MartinMächlerコアRパッケージはparse常に使用するため、皮肉なことに!github.com/wch/r-source/...
geneorama

49

申し訳ありませんが、文字列を評価できるものだと思っている人が多すぎる理由はわかりません。本当に考え方を変える必要があります。一方の文字列ともう一方の式、呼び出し、評価の間のすべての接続を忘れます。

(おそらく)唯一の接続はviaで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月:わかりました、ここに例があります(コメントでは、適切な書式設定はありません)。

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

e5 <- expression(5+5)
str(e5)
# expression(5 + 5)

さらに経験を積むq5と、"call"それe5がaであるのに対し、はである"expression"ことe5[[1]]がわかりq5ます。

identical(q5, e5[[1]])
# [1] TRUE

4
例を挙げていただけますか?rオブジェクトで5 + 5を "保持"する方法を示し、その後、文字とeval(parse(text =)ではなく引用符と置換を使用して評価する方法を教えてください。?
Richard DiSalvo

3
少し迷うかもしれません。いつ10になりますか?それともそれは重要ではありませんか?
Nick S

@RichardDiSalvo:はい、q5 <- quote(5+5)上記式(実際には「呼び出し」)5+5であり、Rオブジェクトですが文字列ではありません。いつでも評価できます。繰り返しますが、using、quote()、substitute()、... 代わりに、 parseはparse(text =。)を使用するよりも直接かつより効率的に呼び出しまたは式を作成します。使用するには、 eval()使用して、罰金でparse(text=*)発生しやすいと建設の呼び出しと比較して、時には非常に非効率的で、それらを操作するエラーます。.. @Nick S:それは eval(q5) あるいはeval(e5) 私たち実行している例では
マーティンMächler

@NickS:10を取得するには、呼び出し/式を評価します(つまり、呼び出しますeval(.))。私の要点は、人々が後で編集される呼び出しを構築するためにparse(text=.)、むしろquote(.)等を使用すべきではないということでしたeval()
MartinMächler、

2
eval(quote())いくつかのケースでeval(parse())動作しますが、うまくいくいくつかのケースでは失敗します。
NelsonGon

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"

2
素敵な機能。evaluate::evaluate実際に結果オブジェクトを返すことによって残された穴を埋めます。これにより、関数はmclapplyを介した呼び出しに使用できるようになります。機能が残っていることを願っています!
russellpierce 2015

@rpierce、ありがとうございます。この関数は当初、2011年にrapportパッケージの一部として作成され、他のいくつかのプロジェクトに加えてrapporter.netサービスでも頻繁に使用されているため、その後も積極的にメンテナンスされています。while :)フィードバックをお寄せいただきありがとうございます。
daroczig


2

同様に使用rlang

eval(parse_expr("5+5"))

3
ここにrlang答えを探しに来ましたが、これが基本的な選択肢よりも優れている場合はどうでしょうか?実際、使用されているコードを詳しく調べると、実際に使用eval(parse(....))したくないコードが使用されていることがわかります。
NelsonGon

4
これらのネガティブだけでなく、その名前も誤解を招くものです。式の評価ではありません。parse_to_exprまたは別の名前で呼び出して、ユーザーが文字引数を意図していることを知っていることを示す必要があります。
IRTFM
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.