Oceń wyrażenie podane jako ciąg znaków

Jestem ciekaw, czy R może używać swojej funkcji eval() do wykonywania obliczeń dostarczanych np. przez ciąg znaków.

Jest to częsty przypadek:

eval("5+5")

Jednak zamiast 10 dostaję:

[1] "5+5"
Jakieś rozwiązanie?
 222
Author: zx8754, 2009-11-16

5 answers

Funkcja eval() oblicza wyrażenie, ale "5+5" jest łańcuchem znaków, a nie wyrażeniem. Użyj parse() z text=<string>, aby zmienić łańcuch znaków na wyrażenie:

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

Wywołanie eval() wywołuje wiele zachowań, niektóre nie są od razu oczywiste:

> 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

Zobacz też tryCatch.

 339
Author: Harlan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:07

Możesz użyć funkcji parse() do konwersji znaków na wyrażenie. Musisz określić, że dane wejściowe to tekst, ponieważ parse domyślnie oczekuje pliku:

eval(parse(text="5+5"))
 83
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-16 17:53:22

Przepraszam, ale nie rozumiem, dlaczego zbyt wiele osób myśli, że łańcuch jest czymś, co można ocenić. Musisz zmienić swoje nastawienie, naprawdę. Zapomnij o wszystkich połączeniach między łańcuchami po jednej stronie a wyrażeniami, wywołaniami, ewaluacją po drugiej stronie.

(prawdopodobnie) jedynym połączeniem jest parse(text = ....) i wszyscy dobrzy Programiści R powinni wiedzieć, że rzadko jest to skuteczny lub bezpieczny sposób konstruowania wyrażeń (lub wywołań). Raczej dowiedz się więcej o substitute(), quote(), i ewentualnie moc używania 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)
[[13]] Grudzień2017: Ok, oto przykład (w komentarzach nie ma ładnego formatowania):
q5 <- quote(5+5)
str(q5)
# language 5 + 5

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

I jeśli będziesz bardziej doświadczony, dowiesz się, że q5 jest "call", podczas gdy e5 jest "expression", a nawet to e5[[1]] jest identyczne z q5:

identical(q5, e5[[1]])
# [1] TRUE
 34
Author: Martin Mächler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-17 13:07:44

Alternatywnie, możesz użyć evals z mojego pakietu pander do przechwytywania danych wyjściowych i wszystkich ostrzeżeń, błędów i innych komunikatów wraz z surowymi wynikami:

> 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"
 15
Author: daroczig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-12 03:46:06

Obecnie można również użyć funkcji lazy_eval z pakietu lazyeval.

> lazyeval::lazy_eval("5+5")
[1] 10
 3
Author: Paweł Kozielski-Romaneczko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-04 00:40:23