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

194

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

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

eval("5+5")

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

[1] "5+5"

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

  • 6
    Несмотря на все ответы, показывающие, как решить эту проблему с помощью синтаксического анализа ... Зачем вам нужно хранить языковые типы в символьной string ? Ответ Мартина Мехлера заслуживает гораздо большего числа голосов.
  • 5
    Спасибо @PetrMatousu. Да, я потрясен, увидев, как ложная информация распространяется на SO сейчас ... людьми, которые голосуют за поддельные решения eval(parse(text = *)) .
Показать ещё 1 комментарий
Теги:
eval
r-faq

5 ответов

313
Лучший ответ

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

  • 17
    Как отмечает Шейн ниже: «Вы должны указать, что ввод является текстом, потому что parse ожидает файл по умолчанию»
  • 0
    побочные эффекты использования eval (parse) должны быть указаны. Например, если у вас есть предопределенное имя переменной, равное «David», и вы переназначаете его, используя eval (parse (text = "name") == "Alexander", вы получите ошибку, потому что eval & parse не возвращают R выражение, которое можно оценить.
73

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

eval(parse(text="5+5"))
  • 5
    > fortunes :: fortune ("answer is parse") Если ответ - parse (), обычно вы должны переосмыслить вопрос. - Томас Ламли R-help (февраль 2005 г.)>
  • 5
    @ MartinMächler Это иронично, потому что основные пакеты R используют parse постоянно! github.com/wch/r-source/...
21

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

Соединение (возможно) только через 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
  • 2
    не могли бы вы привести пример? может быть, вы могли бы показать нам, как «удерживать» 5 + 5 в объекте r, а затем оценить его позже, используя кавычки и подстановки, а не символ и eval (parse (text =)?
  • 2
    Я могу быть немного потерян. В какой момент вы получаете 10? Или это не главное?
Показать ещё 1 комментарий
15

В качестве альтернативы вы можете использовать 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"
  • 0
    Хорошая функция; заполняет дыру, оставленную при evaluate::evaluate , фактически возвращая объект результата; что оставляет вашу функцию пригодной для использования для вызова через mclapply. Я надеюсь, что эта функция останется!
  • 0
    Спасибо, @rpierce. Эта функция была изначально написана в 2011 году как часть нашего пакета rapport , и с тех пор активно поддерживается как интенсивно используемая в нашем сервисе rapporter.net, помимо нескольких других проектов - так что я уверен, что она будет сохраняться для некоторое время :) Я рад, что вы нашли это полезным, спасибо за ваши добрые отзывы.
1

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню