Оценить выражение, данное как строка

Мне любопытно узнать, может ли R использовать свою функцию eval() для выполнения вычислений, предоставленных, например. строка.

Это обычный случай:

eval("5+5")

Однако вместо 10 я получаю:

[1] "5+5"

Любое решение?

Ответ 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.

Ответ 2

Вы можете использовать функцию parse() для преобразования символов в выражение. Вам нужно указать, что входной текст является текстовым, потому что parse ожидает файл по умолчанию:

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

Ответ 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)

Dec.2017: Хорошо, вот пример (в комментариях нет хорошего форматирования):

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

Ответ 4

В качестве альтернативы вы можете использовать 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"

Ответ 5

В настоящее время вы также можете использовать функцию lazy_eval из пакета lazyeval.

> lazyeval::lazy_eval("5+5")
[1] 10

Ответ 6

Аналогично, используя rlang:

eval(parse_expr("5+5"))