Apesar de todas as respostas mostrarem como resolver isso com análise ... Por que você precisa armazenar tipos de idioma em um personagem string? A resposta de Martin Mächler deve merecer muito mais votos positivos.
Petr Matousu
7
Obrigado @PetrMatousu. Sim, estou chocado ao ver como as informações erradas se espalham no SO agora ... por pessoas que votam em eval(parse(text = *)) soluções falsas.
Martin Mächler 01/04/19
2
Eu quero executar scripts do formulário:, QQ = c('11','12','13','21','22','23')ie: QQ = c (..., 'ij', ..) com i, j variando em um intervalo que pode variar de execução para execução. Para este e outros exemplos semelhantes, posso escrever o script como paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")e a opção eval(parse(text=...))cria o vetor QQ no ambiente de trabalho, conforme o script. Qual seria a maneira correta do codificador R fazer isso, se não com "text = ..."?
VictorZurkowski
Respostas:
418
A eval()função avalia uma expressão, mas "5+5"é uma sequência, não uma expressão. Use parse()with text=<string>para alterar a string em uma expressão:
Chamar eval()invoca muitos comportamentos, alguns não são imediatamente óbvios:
> 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
Como Shane observa abaixo, "Você precisa especificar que a entrada é texto, porque a análise espera um arquivo por padrão"
PatrickT
1
os efeitos colaterais do uso de eval (análise) devem ser especificados. Por exemplo, se você tiver um nome de variável predefinido igual a "David" e reatribuir usando eval (parse (text = "name") == "Alexander", você receberá um erro porque eval & parse não retornam um Expressão de R que pode ser avaliada.
Crt
1
@NelsonGon: expressões não avaliadas construído usando quote(), bquote()ou as ferramentas mais sofisticadas fornecidas pelo rlangpacote.
Artem Sokolov
@ArtemSokolov Obrigado, de alguma forma, continuo voltando a esta pergunta procurando uma alternativa. Eu olhei, rlangmas o mais próximo que encontrei foi parse_exprquais chamadas, parse_exprsque por sua vez, são iguais a usá parse-las e envolvê-las nas evalquais parece ser a mesma coisa que aqui. Não tenho certeza qual seria a vantagem de usar rlang.
NelsonGon
1
@ NelsonGon: com rlang, você trabalharia diretamente com expressões, não com strings. Nenhuma etapa de análise necessária. Tem duas vantagens. 1. Manipulações de expressão sempre produzirão expressões válidas. Manipulações de strings produzirão apenas strings válidos. Você não saberá se são expressões válidas até que você as analise. 2. Não há equivalente à substitute()classe de funções no mundo das cordas, o que limita severamente sua capacidade de manipular chamadas de função. Considere este invólucro glm . Como seria uma string equivalente?
Artem Sokolov
100
Você pode usar a parse()função para converter os caracteres em uma expressão. Você precisa especificar que a entrada é texto, porque a análise espera um arquivo por padrão:
> fortunas :: fortuna ("resposta é análise") Se a resposta for análise (), você deve repensar a pergunta. - Thomas Lumley R-help (fevereiro de 2005)>
Martin Mächler
13
@ MartinMächler Isso é irônico, porque os principais pacotes R usam parseo tempo todo! github.com/wch/r-source/…
geneorama 30/03
49
Desculpe, mas não entendo por que muitas pessoas acham que uma string é algo que pode ser avaliado. Você deve mudar sua mentalidade, realmente. Esqueça todas as conexões entre seqüências de caracteres de um lado e expressões, chamadas e avaliação do outro lado.
A (possivelmente) única conexão é via parse(text = ....)e todos os bons programadores de R devem saber que esse raramente é um meio eficiente ou seguro para construir expressões (ou chamadas). Em vez disso, aprenda mais sobre substitute(), quote()e possivelmente o poder de usar 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)
Dez.2017: Ok, aqui está um exemplo (nos comentários, não há formatação legal):
Você poderia dar um exemplo? talvez você poderia nos mostrar como "hold on" para 5 + 5 em um objeto r, então avaliá-lo mais tarde, usando cotação e substituto em vez de um personagem e eval (parse (text =)?
Richard DiSalvo
3
Eu posso estar um pouco perdido. Em que ponto você recebe 10? Ou não é esse o ponto?
Nick S
@RichardDiSalvo: sim, q5 <- quote(5+5)acima está a expressão (na verdade, a "chamada") 5+5e é um objeto R, mas não uma string. Você pode avaliar a qualquer momento. Novamente: using, quote (), substitute (), ... em vez disso análise cria chamadas ou expressões direta e com mais eficiência do que via análise (text =.). Usando eval()é fina, usando parse(text=*)é propenso a erros e por vezes bastante ineficiente em comparação com chamadas de construção e manipulá-los .. @ Nick S: É eval(q5) ou eval(e5) em nosso exemplo de execução
Martin Machler
@ Nicks: para obter 10, você avalia a chamada / expressão, ou seja, solicita eval(.)-a. Meu argumento era que as pessoas não deveriam usar, parse(text=.)mas sim quote(.)etc, para construir a chamada que mais tarde será eval()editada.
Martin Mächler 6/08/19
2
eval(quote())funciona em alguns casos, mas falha em alguns casos em eval(parse())que funcionaria bem.
NelsonGon
18
Como alternativa, você pode usar evalsdo meu panderpacote para capturar a saída e todos os avisos, erros e outras mensagens junto com os resultados brutos:
Boa função; preenche um buraco deixado evaluate::evaluateretornando o objeto de resultado; que deixa sua função adequada para uso por chamada via mclapply. Espero que esse recurso permaneça!
russellpierce
Obrigado, @rpierce. Essa função foi originalmente escrita em 2011 como parte de nosso rapportpacote e foi ativamente mantida desde então como sendo muito usada em nosso serviço rapporter.net além de alguns outros projetos - por isso, tenho certeza de que ela permanecerá por um período. while :) Fico feliz que você ache útil, obrigado pelo seu feedback.
daroczig
14
Atualmente você também pode usar a lazy_evalfunção do lazyevalpacote.
Vim aqui à procura de uma rlangresposta, mas e se houver, é a vantagem disso sobre as alternativas básicas? Na verdade, um exame atento do código usado mostra que ele está de fato usando o eval(parse(....))que eu queria evitar.
NelsonGon
4
Não apenas esses negativos, mas seu nome também é enganador. NÃO está avaliando uma expressão. Deve ser chamado parse_to_expr ot outra coisa para indicar que o usuário saberá que ele se destina a argumentos de caracteres.
string
? A resposta de Martin Mächler deve merecer muito mais votos positivos.eval(parse(text = *))
soluções falsas.QQ = c('11','12','13','21','22','23')
ie: QQ = c (..., 'ij', ..) com i, j variando em um intervalo que pode variar de execução para execução. Para este e outros exemplos semelhantes, posso escrever o script comopaste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")
e a opçãoeval(parse(text=...))
cria o vetor QQ no ambiente de trabalho, conforme o script. Qual seria a maneira correta do codificador R fazer isso, se não com "text = ..."?Respostas:
A
eval()
função avalia uma expressão, mas"5+5"
é uma sequência, não uma expressão. Useparse()
withtext=<string>
para alterar a string em uma expressão:Chamar
eval()
invoca muitos comportamentos, alguns não são imediatamente óbvios:Veja também tryCatch .
fonte
quote()
,bquote()
ou as ferramentas mais sofisticadas fornecidas pelorlang
pacote.rlang
mas o mais próximo que encontrei foiparse_expr
quais chamadas,parse_exprs
que por sua vez, são iguais a usáparse
-las e envolvê-las naseval
quais parece ser a mesma coisa que aqui. Não tenho certeza qual seria a vantagem de usarrlang
.rlang
, você trabalharia diretamente com expressões, não com strings. Nenhuma etapa de análise necessária. Tem duas vantagens. 1. Manipulações de expressão sempre produzirão expressões válidas. Manipulações de strings produzirão apenas strings válidos. Você não saberá se são expressões válidas até que você as analise. 2. Não há equivalente àsubstitute()
classe de funções no mundo das cordas, o que limita severamente sua capacidade de manipular chamadas de função. Considere este invólucro glm . Como seria uma string equivalente?Você pode usar a
parse()
função para converter os caracteres em uma expressão. Você precisa especificar que a entrada é texto, porque a análise espera um arquivo por padrão:fonte
parse
o tempo todo! github.com/wch/r-source/…Desculpe, mas não entendo por que muitas pessoas acham que uma string é algo que pode ser avaliado. Você deve mudar sua mentalidade, realmente. Esqueça todas as conexões entre seqüências de caracteres de um lado e expressões, chamadas e avaliação do outro lado.
A (possivelmente) única conexão é via
parse(text = ....)
e todos os bons programadores de R devem saber que esse raramente é um meio eficiente ou seguro para construir expressões (ou chamadas). Em vez disso, aprenda mais sobresubstitute()
,quote()
e possivelmente o poder de usardo.call(substitute, ......)
.Dez.2017: Ok, aqui está um exemplo (nos comentários, não há formatação legal):
e se você tiver mais experiência, aprenderá que
q5
é um"call"
considerandoe5
é um"expression"
, e até issoe5[[1]]
é idêntico aq5
:fonte
q5 <- quote(5+5)
acima está a expressão (na verdade, a "chamada")5+5
e é um objeto R, mas não uma string. Você pode avaliar a qualquer momento. Novamente: using, quote (), substitute (), ... em vez disso análise cria chamadas ou expressões direta e com mais eficiência do que via análise (text =.). Usandoeval()
é fina, usandoparse(text=*)
é propenso a erros e por vezes bastante ineficiente em comparação com chamadas de construção e manipulá-los .. @ Nick S: Éeval(q5)
oueval(e5)
em nosso exemplo de execuçãoeval(.)
-a. Meu argumento era que as pessoas não deveriam usar,parse(text=.)
mas simquote(.)
etc, para construir a chamada que mais tarde seráeval()
editada.eval(quote())
funciona em alguns casos, mas falha em alguns casos emeval(parse())
que funcionaria bem.Como alternativa, você pode usar
evals
do meupander
pacote para capturar a saída e todos os avisos, erros e outras mensagens junto com os resultados brutos:fonte
evaluate::evaluate
retornando o objeto de resultado; que deixa sua função adequada para uso por chamada via mclapply. Espero que esse recurso permaneça!rapport
pacote e foi ativamente mantida desde então como sendo muito usada em nosso serviço rapporter.net além de alguns outros projetos - por isso, tenho certeza de que ela permanecerá por um período. while :) Fico feliz que você ache útil, obrigado pelo seu feedback.Atualmente você também pode usar a
lazy_eval
função dolazyeval
pacote.fonte
Da mesma forma, usando
rlang
:fonte
rlang
resposta, mas e se houver, é a vantagem disso sobre as alternativas básicas? Na verdade, um exame atento do código usado mostra que ele está de fato usando oeval(parse(....))
que eu queria evitar.