Оценить выражение в виде строки - PullRequest
251 голосов
/ 16 ноября 2009

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

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

eval("5+5")

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

[1] "5+5"

Есть решение?

Ответы [ 6 ]

371 голосов
/ 16 ноября 2009

Функция 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 .

87 голосов
/ 16 ноября 2009

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

eval(parse(text="5+5"))
41 голосов
/ 20 октября 2016

Извините, но я не понимаю, почему слишком много людей даже думают, что строка - это то, что можно оценить. Вы должны изменить свое мышление, правда. Забудьте все связи между строками на одной стороне и выражениями, вызовами, оценкой на другой стороне.

(возможно) единственное соединение - через 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: Хорошо, вот пример (в комментариях нет хорошего форматирования):

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
16 голосов
/ 12 октября 2015

В качестве альтернативы, вы можете использовать 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"
11 голосов
/ 04 февраля 2018

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

> lazyeval::lazy_eval("5+5")
[1] 10
1 голос
/ 13 апреля 2019

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

eval(parse_expr("5+5"))
...