Вычислить выражение, заданное в виде строки
Вопрос
Мне любопытно узнать, может ли R использовать свой eval()
функция для выполнения вычислений, предоставляемая, например,струна.
Это обычный случай:
eval("5+5")
Однако вместо 10 я получаю:
[1] "5+5"
Есть какое-нибудь решение?
Решение
В 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
Смотрите также Пробный улов.
Другие советы
Вы можете использовать parse()
функция для преобразования символов в выражение.Вам нужно указать, что входными данными является текст, поскольку parse по умолчанию ожидает файл:
eval(parse(text="5+5"))
Извините, но я не понимаю, почему слишком много людей вообще думают, что строка - это нечто, что можно оценить.Вы действительно должны изменить свое мышление.Забудьте обо всех связях между строками с одной стороны и выражениями, вызовами, вычислениями с другой стороны.
(Возможно) единственное соединение осуществляется через 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
В качестве альтернативы вы можете использовать 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"
В настоящее время вы также можете использовать lazy_eval
функция из lazyeval
посылка.
> lazyeval::lazy_eval("5+5")
[1] 10
Аналогично используя rlang
:
eval(parse_expr("5+5"))