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? 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.
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"))
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
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"
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
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