Bewerten Sie den als Zeichenfolge angegebenen Ausdruck


283

Ich bin gespannt, ob R seine eval()Funktion verwenden kann, um Berechnungen durchzuführen, die beispielsweise von einer Zeichenfolge bereitgestellt werden.

Dies ist ein häufiger Fall:

eval("5+5")

Anstelle von 10 bekomme ich jedoch:

[1] "5+5"

Irgendeine Lösung?


6
Trotz aller Antworten, die zeigen, wie man das mit Parse löst ... Warum müssen Sie Sprachtypen in einem Zeichen speichern string? Die Antwort von Martin Mächler sollte viel mehr Stimmen verdienen.
Petr Matousu

7
Vielen Dank, dass Sie @PetrMatousu. Ja, ich bin schockiert zu sehen, wie falsche Informationen jetzt auf SO verbreitet werden ... von Leuten, die eval(parse(text = *)) gefälschte Lösungen befürworten .
Martin Mächler

2
Ich möchte Skripte der folgenden Form ausführen: QQ = c('11','12','13','21','22','23')dh QQ = c (..., 'ij', ..), wobei i, j in einem Bereich variieren, der von Lauf zu Lauf variieren kann. Für dieses und ähnliche Beispiele kann ich das Skript als schreiben paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep=""), und die Option eval(parse(text=...))erstellt den Vektor QQ in der Arbeitsumgebung gemäß dem Skript. Was wäre der richtige R-Codierer, um dies zu tun, wenn nicht mit "text = ..."?
VictorZurkowski

Antworten:


417

Die eval()Funktion wertet einen Ausdruck aus, "5+5"ist jedoch eine Zeichenfolge und kein Ausdruck. Verwenden Sie parse()mit text=<string>, um die Zeichenfolge in einen Ausdruck zu ändern:

> eval(parse(text="5+5"))
[1] 10
> class("5+5")
[1] "character"
> class(parse(text="5+5"))
[1] "expression"

Das Aufrufen eval()ruft viele Verhaltensweisen hervor, einige sind nicht sofort offensichtlich:

> 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

Siehe auch tryCatch .


27
Wie Shane unten bemerkt: "Sie müssen angeben, dass die Eingabe Text ist, da Parse standardmäßig eine Datei erwartet"
PatrickT

1
Die Nebenwirkungen der Verwendung von eval (parse) sollten angegeben werden. Wenn Sie eine vordefinierte Variable beispielsweise Name gleich „David“ und Sie neu zuweisen mit eval (parse (text = „name“) == „Alexander“, wird eine Fehlermeldung angezeigt , weil eval & Parse nicht eine Rückkehr R-Ausdruck, der ausgewertet werden kann.
Crt

1
@NelsonGon: Nicht bewertete Ausdrücke quote(), die bquote()mit oder den komplexeren Tools des rlangPakets erstellt wurden.
Artem Sokolov

@ArtemSokolov Danke, ich komme irgendwie immer wieder auf diese Frage zurück und suche nach einer Alternative. Ich habe mir angesehen, rlangaber das Nächste, was ich gefunden habe, war, parse_exprwelche Anrufe parse_exprsdas Gleiche sind wie das Verwenden parseund Einwickeln, evalwas anscheinend dasselbe ist wie hier. Ich bin mir nicht sicher, welchen Vorteil die Verwendung hätte rlang.
NelsonGon

1
@ NelsonGon: Mit rlangwürden Sie direkt mit Ausdrücken arbeiten, nicht mit Zeichenfolgen. Kein Analyseschritt erforderlich. Es hat zwei Vorteile. 1. Ausdrucksmanipulationen erzeugen immer gültige Ausdrücke. String-Manipulationen erzeugen nur gültige Strings. Sie werden nicht wissen, ob es sich um gültige Ausdrücke handelt, bis Sie sie analysieren. 2. Es gibt kein Äquivalent zur substitute()Funktionsklasse in der String-Welt, was Ihre Fähigkeit, Funktionsaufrufe zu manipulieren, stark einschränkt. Betrachten Sie diesen glm-Wrapper . Wie würde ein String-Äquivalent aussehen?
Artem Sokolov

99

Mit der parse()Funktion können Sie die Zeichen in einen Ausdruck konvertieren. Sie müssen angeben, dass die Eingabe Text ist, da parse standardmäßig eine Datei erwartet:

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

7
> Fortunes :: Fortune ("Antwort ist Parse") Wenn die Antwort Parse () ist, sollten Sie die Frage normalerweise überdenken. - Thomas Lumley R-Hilfe (Februar 2005)>
Martin Mächler

13
@ MartinMächler Das ist ironisch, denn die Core-R-Pakete nutzen parseständig! github.com/wch/r-source/…
geneorama

49

Tut mir leid, aber ich verstehe nicht, warum zu viele Leute glauben, dass eine Zeichenfolge bewertet werden kann. Sie müssen Ihre Einstellung wirklich ändern. Vergessen Sie alle Verbindungen zwischen Zeichenfolgen auf der einen Seite und Ausdrücken, Aufrufen und Auswertungen auf der anderen Seite.

Die (möglicherweise) einzige Verbindung ist über parse(text = ....)und alle guten R-Programmierer sollten wissen, dass dies selten ein effizientes oder sicheres Mittel ist, um Ausdrücke (oder Aufrufe) zu konstruieren. Vielmehr erfahren Sie mehr über substitute(), quote()und möglicherweise die Macht der Verwendung 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)

Dez.2017: Ok, hier ist ein Beispiel (in Kommentaren gibt es keine nette Formatierung):

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

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

und wenn Sie mehr Erfahrung haben, werden Sie lernen, dass dies q5eine "call"Weile e5ist "expression", und selbst das e5[[1]]ist identisch mit q5:

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

4
Könnten Sie ein Beispiel geben? Vielleicht könnten Sie uns zeigen, wie man 5 + 5 in einem r-Objekt "festhält" und es später mit Zitat und Ersatz anstelle eines Zeichens und einer Bewertung (parse (text =)?)
bewertet

3
Ich kann ein wenig verloren sein. Ab wann bekommst du 10? Oder ist das nicht der Punkt?
Nick S

@RichardDiSalvo: Ja, q5 <- quote(5+5)oben steht der Ausdruck (eigentlich der "Aufruf") 5+5und es ist ein R-Objekt, aber keine Zeichenfolge. Sie können es jederzeit auswerten. Nochmals: using, quote (), replace (), ... stattdessen erstellt parse Aufrufe oder Ausdrücke direkt und effizienter als via parse (text =.). Die Verwendung eval()ist in Ordnung, die Verwendung parse(text=*)ist fehleranfällig und manchmal im Vergleich zu Konstruktionsaufrufen und deren Manipulation recht ineffizient. @Nick S: Es ist eval(q5) oder eval(e5) in unserem laufenden Beispiel
Martin Mächler

@NickS: Um 10 zu erhalten, werten Sie den Aufruf / Ausdruck aus, dh rufen eval(.)Sie ihn auf. Mein Punkt war, dass die Leute nicht verwenden sollten parse(text=.), sondern quote(.)usw., um den Anruf zu konstruieren, der später eval()bearbeitet wird.
Martin Mächler

2
eval(quote())funktioniert in einigen Fällen, schlägt aber in einigen Fällen fehl, in denen eval(parse())es gut funktionieren würde.
NelsonGon

18

Alternativ können Sie evalsaus meinem panderPaket die Ausgabe und alle Warnungen, Fehler und anderen Meldungen zusammen mit den Rohergebnissen erfassen:

> 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
Gute Funktion; füllt ein Loch, das durch das evaluate::evaluatetatsächliche Zurückgeben des Ergebnisobjekts übrig bleibt ; Damit ist Ihre Funktion für den Anruf über mclapply geeignet. Ich hoffe, dass diese Funktion erhalten bleibt!
Russellpierce

Vielen Dank, @rpierce. Diese Funktion wurde ursprünglich im Jahr 2011 als Teil unseres rapportPakets geschrieben und wurde seitdem aktiv gepflegt, da sie neben einigen anderen Projekten auch in unserem rapporter.net- Dienst stark genutzt wird während :) Ich bin froh, dass Sie es nützlich finden, danke für Ihr freundliches Feedback.
Daroczig


2

Ähnlich mit rlang:

eval(parse_expr("5+5"))

3
Kam hier auf der Suche nach einer rlangAntwort, aber was ist, wenn überhaupt, der Vorteil dieser gegenüber Basisalternativen? Tatsächlich zeigt eine genaue Untersuchung des verwendeten Codes, dass er tatsächlich verwendet wird, eval(parse(....))was ich vermeiden wollte.
NelsonGon

4
Nicht nur diese Negative, sondern auch sein Name ist irreführend. Es wird KEIN Ausdruck ausgewertet. Sollte parse_to_expr oder etwas anderes heißen, um anzuzeigen, dass der Benutzer weiß, dass es für Zeichenargumente vorgesehen ist.
IRTFM
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.