Malgré toutes les réponses montrant comment résoudre ce problème avec l'analyse ... Pourquoi avez-vous besoin de stocker les types de langue dans un caractère string? La réponse de Martin Mächler devrait mériter beaucoup plus de votes positifs.
Petr Matousu
7
Merci @PetrMatousu. Oui, je suis choqué de voir comment les informations erronées sont diffusées sur SO maintenant .. par des gens qui votent pour de eval(parse(text = *)) fausses solutions.
Martin Mächler
2
Je veux exécuter des scripts de la forme:, QQ = c('11','12','13','21','22','23')c'est-à-dire: QQ = c (..., 'ij', ..) avec i, j variant sur une plage qui peut varier d'une exécution à l'autre. Pour cela et des exemples similaires, je peux écrire le script en tant que paste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep=""), et l'option eval(parse(text=...))crée le vecteur QQ dans l'environnement de travail conformément au script. Quelle serait la bonne façon pour le codeur R de le faire, sinon avec "text = ..."?
VictorZurkowski
Réponses:
419
La eval()fonction évalue une expression, mais "5+5"est une chaîne, pas une expression. Utilisez parse()avec text=<string>pour changer la chaîne en une expression:
L'appel eval()appelle de nombreux comportements, certains ne sont pas immédiatement évidents:
> 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
Comme Shane le note ci-dessous, "Vous devez spécifier que l'entrée est du texte, car parse attend un fichier par défaut"
PatrickT
1
les effets secondaires de l'utilisation d'eval (analyse) doivent être spécifiés. Par exemple, si vous avez un nom de variable prédéfini égal à "David" et que vous réaffectez en utilisant eval (parse (text = "name") == "Alexander", vous obtiendrez une erreur car eval & parse ne renvoie pas de Expression R qui peut être évaluée
Crt
1
@NelsonGon: expressions non évaluées construites à l'aide de quote(), bquote()ou des outils plus sophistiqués fournis par le rlangpackage.
Artem Sokolov
@ArtemSokolov Merci, je reviens en quelque sorte à cette question à la recherche d'une alternative. J'ai regardé, rlangmais le plus proche que j'ai trouvé était les parse_exprappels parse_exprsqui, à leur tour, sont les mêmes que l'utilisation parseet l'enveloppement, ce evalqui semble être la même chose que celle faite ici. Je ne sais pas quel serait l'avantage d'utiliser rlang.
NelsonGon
1
@NelsonGon: avec rlang, vous travailleriez directement avec des expressions, pas avec des chaînes. Aucune étape d'analyse nécessaire. Cela présente deux avantages. 1. Les manipulations d'expression produisent toujours des expressions valides. Les manipulations de chaînes ne produiront que des chaînes valides. Vous ne saurez pas si ce sont des expressions valides tant que vous ne les aurez pas analysées. 2. Il n'y a pas d'équivalent à la substitute()classe de fonctions dans le monde des chaînes, ce qui limite considérablement votre capacité à manipuler les appels de fonction. Considérez ce wrapper glm . À quoi ressemblerait une chaîne équivalente?
Artem Sokolov
100
Vous pouvez utiliser la parse()fonction pour convertir les caractères en une expression. Vous devez spécifier que l'entrée est du texte, car l'analyse attend un fichier par défaut:
> fortunes :: fortune ("answer is parse") Si la réponse est parse (), vous devriez généralement repenser la question. - Thomas Lumley R-help (février 2005)>
Martin Mächler
13
@ MartinMächler C'est ironique, car les packages R principaux utilisent parsetout le temps! github.com/wch/r-source/…
geneorama
49
Désolé mais je ne comprends pas pourquoi trop de gens pensent même qu'une chaîne est quelque chose qui pourrait être évaluée. Vous devez vraiment changer votre état d'esprit. Oubliez toutes les connexions entre les chaînes d'un côté et les expressions, les appels et l'évaluation de l'autre côté.
La (éventuellement) seule connexion est via parse(text = ....)et tous les bons programmeurs R doivent savoir que c'est rarement un moyen efficace ou sûr de construire des expressions (ou des appels). Apprenez plutôt sur substitute(), quote()et peut-être sur la puissance de l'utilisation 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: Ok, voici un exemple (dans les commentaires, il n'y a pas de mise en forme sympa):
Pouvez-vous donner un exemple? peut-être pourriez-vous nous montrer comment "s'accrocher" à 5 + 5 dans un objet r, puis l'évaluer plus tard, en utilisant des guillemets et des substituts plutôt qu'un caractère et une évaluation (analyse (texte =)?
Richard DiSalvo
3
Je suis peut-être un peu perdu. À quel moment en avez-vous 10? Ou n'est-ce pas le but?
Nick S
@RichardDiSalvo: oui, q5 <- quote(5+5)au - dessus se trouve l'expression (en fait "l'appel") 5+5et c'est un objet R, mais pas une chaîne. Vous pouvez l'évaluer à tout moment. Encore une fois: utiliser, quote (), substitute (), ... à la place, l' analyse crée des appels ou des expressions directement et plus efficacement que via l'analyse (text =.). L'utilisation eval()est très bien, l'utilisation parse(text=*)est sujette aux erreurs et parfois assez inefficace par rapport aux appels de construction et les manipuler .. @ Nick S: C'est eval(q5) ou eval(e5) dans notre exemple en cours
Martin Mächler
@ NickS: pour obtenir 10, vous évaluez l'appel / l'expression, c'est-à-dire que vous l'appelez eval(.). Mon point était que les gens ne devraient pas utiliser parse(text=.)mais plutôt quote(.)etc, pour construire l'appel qui sera eval()édité plus tard .
Martin Mächler
2
eval(quote())fonctionne dans quelques cas mais échouera dans certains cas où eval(parse())cela fonctionnerait bien.
NelsonGon
18
Alternativement, vous pouvez utiliser à evalspartir de mon panderpackage pour capturer la sortie et tous les avertissements, erreurs et autres messages ainsi que les résultats bruts:
Belle fonction; remplit un trou laissé evaluate::evaluateen retournant réellement l'objet résultat; qui laisse votre fonction utilisable pour l'appel via mclapply. J'espère que cette fonctionnalité restera!
russellpierce
Merci, @rpierce. Cette fonction a été initialement écrite en 2011 dans le cadre de notre rapportpackage, et a été activement maintenue depuis lors comme étant fortement utilisée dans notre service rapporter.net en plus de quelques autres projets également - donc je suis sûr qu'elle restera maintenue pendant un tout :) Je suis heureux que vous le trouviez utile, merci pour vos aimables commentaires.
daroczig
14
De nos jours, vous pouvez également utiliser la lazy_evalfonction du lazyevalpackage.
Je suis venu ici à la recherche d'une rlangréponse, mais quel est, le cas échéant, l'avantage de cette solution de base? En fait, un examen attentif du code utilisé montre qu'il est en fait d'utiliser eval(parse(....))ce que je voulais éviter.
NelsonGon
4
Non seulement ces points négatifs, mais son nom est également trompeur. Ce n'est PAS l'évaluation d'une expression. Doit être appelé parse_to_expr ou autre chose pour indiquer que l'utilisateur saura qu'il est destiné aux arguments de caractères.
string
? La réponse de Martin Mächler devrait mériter beaucoup plus de votes positifs.eval(parse(text = *))
fausses solutions.QQ = c('11','12','13','21','22','23')
c'est-à-dire: QQ = c (..., 'ij', ..) avec i, j variant sur une plage qui peut varier d'une exécution à l'autre. Pour cela et des exemples similaires, je peux écrire le script en tant quepaste( "QQ = c('", paste(rep(1:2,each=3),1:3, sep="", collapse="','"), "')",sep="")
, et l'optioneval(parse(text=...))
crée le vecteur QQ dans l'environnement de travail conformément au script. Quelle serait la bonne façon pour le codeur R de le faire, sinon avec "text = ..."?Réponses:
La
eval()
fonction évalue une expression, mais"5+5"
est une chaîne, pas une expression. Utilisezparse()
avectext=<string>
pour changer la chaîne en une expression:L'appel
eval()
appelle de nombreux comportements, certains ne sont pas immédiatement évidents:Voir aussi tryCatch .
la source
quote()
,bquote()
ou des outils plus sophistiqués fournis par lerlang
package.rlang
mais le plus proche que j'ai trouvé était lesparse_expr
appelsparse_exprs
qui, à leur tour, sont les mêmes que l'utilisationparse
et l'enveloppement, ceeval
qui semble être la même chose que celle faite ici. Je ne sais pas quel serait l'avantage d'utiliserrlang
.rlang
, vous travailleriez directement avec des expressions, pas avec des chaînes. Aucune étape d'analyse nécessaire. Cela présente deux avantages. 1. Les manipulations d'expression produisent toujours des expressions valides. Les manipulations de chaînes ne produiront que des chaînes valides. Vous ne saurez pas si ce sont des expressions valides tant que vous ne les aurez pas analysées. 2. Il n'y a pas d'équivalent à lasubstitute()
classe de fonctions dans le monde des chaînes, ce qui limite considérablement votre capacité à manipuler les appels de fonction. Considérez ce wrapper glm . À quoi ressemblerait une chaîne équivalente?Vous pouvez utiliser la
parse()
fonction pour convertir les caractères en une expression. Vous devez spécifier que l'entrée est du texte, car l'analyse attend un fichier par défaut:la source
parse
tout le temps! github.com/wch/r-source/…Désolé mais je ne comprends pas pourquoi trop de gens pensent même qu'une chaîne est quelque chose qui pourrait être évaluée. Vous devez vraiment changer votre état d'esprit. Oubliez toutes les connexions entre les chaînes d'un côté et les expressions, les appels et l'évaluation de l'autre côté.
La (éventuellement) seule connexion est via
parse(text = ....)
et tous les bons programmeurs R doivent savoir que c'est rarement un moyen efficace ou sûr de construire des expressions (ou des appels). Apprenez plutôt sursubstitute()
,quote()
et peut-être sur la puissance de l'utilisationdo.call(substitute, ......)
.Dec.2017: Ok, voici un exemple (dans les commentaires, il n'y a pas de mise en forme sympa):
et si vous êtes plus expérimenté, vous apprendrez que
q5
c'est un"call"
alors quee5
c'est un"expression"
, et même celae5[[1]]
est identique àq5
:la source
q5 <- quote(5+5)
au - dessus se trouve l'expression (en fait "l'appel")5+5
et c'est un objet R, mais pas une chaîne. Vous pouvez l'évaluer à tout moment. Encore une fois: utiliser, quote (), substitute (), ... à la place, l' analyse crée des appels ou des expressions directement et plus efficacement que via l'analyse (text =.). L'utilisationeval()
est très bien, l'utilisationparse(text=*)
est sujette aux erreurs et parfois assez inefficace par rapport aux appels de construction et les manipuler .. @ Nick S: C'esteval(q5)
oueval(e5)
dans notre exemple en courseval(.)
. Mon point était que les gens ne devraient pas utiliserparse(text=.)
mais plutôtquote(.)
etc, pour construire l'appel qui seraeval()
édité plus tard .eval(quote())
fonctionne dans quelques cas mais échouera dans certains cas oùeval(parse())
cela fonctionnerait bien.Alternativement, vous pouvez utiliser à
evals
partir de monpander
package pour capturer la sortie et tous les avertissements, erreurs et autres messages ainsi que les résultats bruts:la source
evaluate::evaluate
en retournant réellement l'objet résultat; qui laisse votre fonction utilisable pour l'appel via mclapply. J'espère que cette fonctionnalité restera!rapport
package, et a été activement maintenue depuis lors comme étant fortement utilisée dans notre service rapporter.net en plus de quelques autres projets également - donc je suis sûr qu'elle restera maintenue pendant un tout :) Je suis heureux que vous le trouviez utile, merci pour vos aimables commentaires.De nos jours, vous pouvez également utiliser la
lazy_eval
fonction dulazyeval
package.la source
De même, en utilisant
rlang
:la source
rlang
réponse, mais quel est, le cas échéant, l'avantage de cette solution de base? En fait, un examen attentif du code utilisé montre qu'il est en fait d'utilisereval(parse(....))
ce que je voulais éviter.