Несмотря на все ответы, показывающие, как решить эту проблему с помощью синтаксического анализа ... Зачем вам нужно хранить языковые типы в символе string? Ответ Мартина Мехлера заслуживает гораздо большего числа голосов.
Петр Матоусу
7
Спасибо @PetrMatousu. Да, я потрясен, увидев, как ложная информация распространяется на SO сейчас ... людьми, которые голосуют за eval(parse(text = *)) поддельные решения.
Мартин Мехлер
2
Я хочу запускать сценарии в форме:, QQ = c('11','12','13','21','22','23')то есть: QQ = c (..., 'ij', ..) с i, j, варьирующимся в диапазоне, который может варьироваться от запуска к запуску. Для этого и подобных примеров я могу написать сценарий как paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep=""), а опция eval(parse(text=...))создает вектор QQ в рабочей среде согласно сценарию. Каков будет правильный способ кодера R сделать это, если не с "text = ..."?
ВикторЗурковский,
Ответы:
419
eval()Функция вычисляет выражение, но "5+5"это строка, а не выражение. Используйте parse()с, text=<string>чтобы изменить строку в выражение:
Вызов 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
Как отмечает Шейн ниже: «Вы должны указать, что ввод является текстом, потому что синтаксический анализ ожидает файл по умолчанию»
PatrickT
1
побочные эффекты использования eval (parse) должны быть указаны. Например, если у вас есть предопределенное имя переменной, равное «David», и вы переназначаете его, используя eval (parse (text = "name") == "Alexander", вы получите ошибку, потому что eval & parse не возвращают Выражение R, которое можно оценить.
Crt
1
@NelsonGon: невычисленного выражения построены с использованием quote(), bquote()или более сложные инструменты , предоставляемые rlangпакетом.
Артем Соколов
@ArtemSokolov Спасибо, я как-то продолжаю возвращаться к этому вопросу в поисках альтернативы. Я посмотрел, rlangно самое близкое, что я нашел, было то, parse_exprкакие вызовы, parse_exprsв свою очередь, такие же, как использование parseи обертывание, в evalкоторых, кажется, то же самое, что и здесь. Я не уверен, какое преимущество будет иметь использование rlang.
НельсонГон
1
@NelsonGon: с rlang, вы бы работали напрямую с выражениями, а не со строками. Нет необходимости разбирать шаг. У этого есть два преимущества. 1. Манипуляции с выражениями всегда будут давать правильные выражения. Манипуляции со строками будут производить только допустимые строки. Вы не будете знать, являются ли они действительными выражениями, пока не проанализируете их. 2. В substitute()мире строк нет эквивалента классу функций, который сильно ограничивает вашу способность манипулировать вызовами функций. Посмотрите на эту упаковку GLM . Как будет выглядеть строковый эквивалент?
Артем Соколов
100
Вы можете использовать parse()функцию для преобразования символов в выражение. Вы должны указать, что входные данные являются текстовыми, потому что parse ожидает файл по умолчанию:
> fortunes :: fortune ("answer is parse") Если ответ - parse (), обычно вы должны переосмыслить вопрос. - Томас Ламли R-help (февраль 2005 г.)>
Мартин Мехлер
13
@ MartinMächler Это иронично, потому что пакеты core R используются parseпостоянно! github.com/wch/r-source/...
geneorama
49
Извините, но я не понимаю, почему слишком многие люди думают, что строка - это то, что можно оценить. Вы должны изменить свое мышление, правда. Забудьте все связи между строками с одной стороны и выражениями, вызовами, оценкой с другой стороны.
Соединение (возможно) только через, 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: Хорошо, вот пример (в комментариях нет хорошего форматирования):
не могли бы вы привести пример? может быть, вы могли бы показать нам, как «удерживать» 5 + 5 в r-объекте, а затем оценить его позже, используя кавычки и подстановки, а не символ и eval (parse (text =)?
Richard DiSalvo
3
Я могу быть немного потерян. В какой момент вы получаете 10? Или это не главное?
Ник С
@RichardDiSalvo: да, q5 <- quote(5+5)выше это выражение (на самом деле "call"), 5+5и это объект R, но не строка. Вы можете оценить это в любое время. Снова: использование, quote (), substitute (), ... вместо этого parse создает вызовы или выражения напрямую и более эффективно, чем через parse (text =.). Использование eval()в порядке, использование parse(text=*)подвержено ошибкам и иногда совершенно неэффективно по сравнению с вызовами конструкции и манипулированием ими .. @ Ник С: Это eval(q5) или eval(e5) в нашем работающем примере
Мартин Мехлер
@NickS: чтобы получить 10, вы оцениваете вызов / выражение, т. Е. Вызываете eval(.)его. Моя точка зрения заключалась в том, что люди не должны использовать, parse(text=.)а, скорее, и quote(.)т.д., чтобы создать вызов, который позже будет eval()редактироваться.
Мартин Мехлер
2
eval(quote())работает в нескольких случаях, но не получится в некоторых случаях, когда eval(parse())будет работать хорошо.
НельсонГон
18
Кроме того, вы можете использовать evalsиз моего panderпакета, чтобы захватить вывод и все предупреждения, ошибки и другие сообщения вместе с необработанными результатами:
Хорошая функция; заполняет оставленное отверстие evaluate::evaluate, фактически возвращая объект результата; что делает вашу функцию пригодной для использования через mclapply. Я надеюсь, что эта функция останется!
Расселпирс
Спасибо, @rpierce. Эта функция была изначально написана в 2011 году как часть нашего rapportпакета, и с тех пор активно поддерживается как интенсивно используемая в нашем сервисе rapporter.net, помимо нескольких других проектов - так что я уверен, что она будет сохраняться в течение некоторого времени. пока :) Я рад, что вы нашли это полезным, спасибо за ваши добрые отзывы.
Дароциг
14
В настоящее время вы также можете использовать lazy_evalфункцию из lazyevalпакета.
Пришел сюда в поисках rlangответа, но что если есть преимущество в этом по сравнению с базовыми альтернативами? На самом деле, тщательное изучение используемого кода показывает, что он на самом деле использует то, eval(parse(....))чего я хотел избежать.
НельсонГон
4
Не только эти негативы, но и его название также вводит в заблуждение. Это НЕ оценка выражения. Должен называться parse_to_expr или как-то еще, чтобы указать, что пользователь будет знать, что он предназначен для символьных аргументов.
string
? Ответ Мартина Мехлера заслуживает гораздо большего числа голосов.eval(parse(text = *))
поддельные решения.QQ = c('11','12','13','21','22','23')
то есть: QQ = c (..., 'ij', ..) с i, j, варьирующимся в диапазоне, который может варьироваться от запуска к запуску. Для этого и подобных примеров я могу написать сценарий какpaste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")
, а опцияeval(parse(text=...))
создает вектор QQ в рабочей среде согласно сценарию. Каков будет правильный способ кодера R сделать это, если не с "text = ..."?Ответы:
eval()
Функция вычисляет выражение, но"5+5"
это строка, а не выражение. Используйтеparse()
с,text=<string>
чтобы изменить строку в выражение:Вызов
eval()
вызывает много поведений, некоторые не сразу очевидны:Смотрите также tryCatch .
источник
quote()
,bquote()
или более сложные инструменты , предоставляемыеrlang
пакетом.rlang
но самое близкое, что я нашел, было то,parse_expr
какие вызовы,parse_exprs
в свою очередь, такие же, как использованиеparse
и обертывание, вeval
которых, кажется, то же самое, что и здесь. Я не уверен, какое преимущество будет иметь использованиеrlang
.rlang
, вы бы работали напрямую с выражениями, а не со строками. Нет необходимости разбирать шаг. У этого есть два преимущества. 1. Манипуляции с выражениями всегда будут давать правильные выражения. Манипуляции со строками будут производить только допустимые строки. Вы не будете знать, являются ли они действительными выражениями, пока не проанализируете их. 2. Вsubstitute()
мире строк нет эквивалента классу функций, который сильно ограничивает вашу способность манипулировать вызовами функций. Посмотрите на эту упаковку GLM . Как будет выглядеть строковый эквивалент?Вы можете использовать
parse()
функцию для преобразования символов в выражение. Вы должны указать, что входные данные являются текстовыми, потому что parse ожидает файл по умолчанию:источник
parse
постоянно! github.com/wch/r-source/...Извините, но я не понимаю, почему слишком многие люди думают, что строка - это то, что можно оценить. Вы должны изменить свое мышление, правда. Забудьте все связи между строками с одной стороны и выражениями, вызовами, оценкой с другой стороны.
Соединение (возможно) только через,
parse(text = ....)
и все хорошие программисты на R должны знать, что это редко является эффективным или безопасным средством для создания выражений (или вызовов). Скорее узнать больше оsubstitute()
,quote()
и , возможно , власть использованияdo.call(substitute, ......)
.Декабрь 2017: Хорошо, вот пример (в комментариях нет хорошего форматирования):
и если вы получите больше опыта вы узнаете , что
q5
это в"call"
то время какe5
это"expression"
, и даже то , чтоe5[[1]]
идентичноq5
:источник
q5 <- quote(5+5)
выше это выражение (на самом деле "call"),5+5
и это объект R, но не строка. Вы можете оценить это в любое время. Снова: использование, quote (), substitute (), ... вместо этого parse создает вызовы или выражения напрямую и более эффективно, чем через parse (text =.). Использованиеeval()
в порядке, использованиеparse(text=*)
подвержено ошибкам и иногда совершенно неэффективно по сравнению с вызовами конструкции и манипулированием ими .. @ Ник С: Этоeval(q5)
илиeval(e5)
в нашем работающем примереeval(.)
его. Моя точка зрения заключалась в том, что люди не должны использовать,parse(text=.)
а, скорее, иquote(.)
т.д., чтобы создать вызов, который позже будетeval()
редактироваться.eval(quote())
работает в нескольких случаях, но не получится в некоторых случаях, когдаeval(parse())
будет работать хорошо.Кроме того, вы можете использовать
evals
из моегоpander
пакета, чтобы захватить вывод и все предупреждения, ошибки и другие сообщения вместе с необработанными результатами:источник
evaluate::evaluate
, фактически возвращая объект результата; что делает вашу функцию пригодной для использования через mclapply. Я надеюсь, что эта функция останется!rapport
пакета, и с тех пор активно поддерживается как интенсивно используемая в нашем сервисе rapporter.net, помимо нескольких других проектов - так что я уверен, что она будет сохраняться в течение некоторого времени. пока :) Я рад, что вы нашли это полезным, спасибо за ваши добрые отзывы.В настоящее время вы также можете использовать
lazy_eval
функцию изlazyeval
пакета.источник
Аналогично используя
rlang
:источник
rlang
ответа, но что если есть преимущество в этом по сравнению с базовыми альтернативами? На самом деле, тщательное изучение используемого кода показывает, что он на самом деле использует то,eval(parse(....))
чего я хотел избежать.