2009-11-16 14 views
202

Sono curioso di sapere se R può utilizzare la sua funzione eval() per eseguire calcoli forniti da ad es. una stringa.Valuta espressione fornita come stringa

Questo è un caso comune:

eval("5+5") 

Tuttavia, invece di 10 ottengo:

[1] "5+5" 

Qualsiasi soluzione?

+5

Nonostante tutte le risposte che mostrano come risolverlo con parse ... Perché è necessario memorizzare i tipi di lingua in un carattere 'stringa'? La risposta di Martin Mächler dovrebbe meritare molti più voti. –

+3

Grazie @PetrMatousu. Sì, sono scioccato nel vedere come le informazioni errate siano diffuse su SO ora .. da persone che invitano a "eval (parse (text = *))" soluzioni false. –

risposta

311

La funzione eval() valuta un'espressione, ma "5+5" è una stringa, non un'espressione. Utilizzare parse() con text=<string> per modificare la stringa in un'espressione:

> eval(parse(text="5+5")) 
[1] 10 
> class("5+5") 
[1] "character" 
> class(parse(text="5+5")) 
[1] "expression" 

Calling eval() invoca molti comportamenti, alcuni non sono immediatamente evidenti:

> 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 

Vedi anche tryCatch.

+16

Come indicato da Shane in basso, "È necessario specificare che l'input è testo, perché parse si aspetta un file per impostazione predefinita " – PatrickT

+0

devono essere specificati gli effetti collaterali dell'utilizzo di eval (analisi). Ad esempio, se hai una variabile predefinita ** nome ** uguale a "David" e riassegni usando eval (parse (text = "name") == "Alexander", riceverai un errore perché eval & parse non restituire un'espressione R che può essere valutata – Crt

73

È possibile utilizzare la funzione parse() per convertire i caratteri in un'espressione. È necessario specificare che l'ingresso è di testo, perché parse si aspetta un file di default:

eval(parse(text="5+5")) 
+4

> fortunes :: fortune ("answer is parse") Se la risposta è parse(), di solito dovresti ripensare alla domanda. - Thomas Lumley R-help (febbraio 2005) > –

+5

@ MartinMächler Questo è ironico, perché i pacchetti di core R usano 'parse' tutto il tempo! https://github.com/wch/r-source/search?utf8=%E2%9C%93&q=extension%3AR+parse&type= – geneorama

15

In alternativa, è possibile utilizzare evals dal mio pacchetto pander per acquisire l'output e tutti gli avvisi, gli errori e altri messaggi insieme ai risultati grezzi:

> 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

Funzione piacevole, riempie un buco lasciato da 'valutare :: valutare' restituendo effettivamente l'oggetto risultato, che lascia la funzione adatta per l'uso per la chiamata tramite mclapply. ! – russellpierce

+0

Grazie, @ rpierce. Questa funzione è stata originariamente scritta nel 2011 come parte del nostro pacchetto "rapport', e da allora è stata attivamente mantenuta come molto utilizzata nel nostro [rapporter.net] (http://rapporter.net) servizio oltre ad alcuni altri progetti - quindi sono sicuro che rimarrà mantenuto per un po ':) Sono felice che lo trovi utile, grazie per il vostro gentile feedback. – daroczig

20

dispiace, ma non capisco il motivo per cui troppe persone ancora pensare che una stringa fosse qualcosa che poteva essere valutata. Devi cambiare la tua mentalità, davvero. Dimentica tutte le connessioni tra stringhe su un lato e le espressioni, le chiamate, la valutazione sull'altro lato.

La (possibilmente) unica connessione è via parse(text = ....) e tutti i buoni programmatori R dovrebbero sapere che questo è raramente un mezzo efficiente o sicuro per costruire espressioni (o chiamate). Piuttosto saperne di più su substitute(), quote(), e forse il potere di usare do.call(substitute, ......)

R> fortune :: fortuna ("risposta è parse")

Se la risposta è parse() di solito si dovrebbe ripensare il domanda. - Thomas Lumley R-aiuto (febbraio 2005)

R>

dicembre2017: Ok, ecco un esempio (nei commenti, non c'è bella formattazione):

R> Q5 < - citazione (5 + 5)
R> str (Q5)
lingua 5 + 5

R> E5 < - espressione (5 + 5)
R> str (e5)
espressione (5 + 5)

e se si ottiene più esperti imparerete che q5 è un "call" dove come e5 è un "expression", e anche che e5 [[1]] è identico a Q5:

R> identici (Q5, e5 [[1]])
[1] TRUE

+0

potresti fare un esempio? forse potresti mostrarci come "resistere" a 5 + 5 in un oggetto r, quindi valutarlo in seguito, usando virgolette e sostituti piuttosto che un carattere ed eval (parse (text =)? –

+0

Potrei essere un po 'perso. A che punto ottieni 10 o non è questo il punto? –

+0

@RichardDiSalvo: sì, 'q5 <- quota (5 + 5)' sopra * è * l'espressione (in realtà la "chiamata") '5 + 5' ed è un oggetto R, ma non una stringa, puoi valutarlo in qualsiasi momento. Di nuovo: using, quote(), sostituto(), ... ** invece ** parse crea chiamate o espressioni direttamente e in modo più efficiente che tramite parse (text =.). L'uso di 'eval()' va bene, usando 'parse (text = *)' è soggetto a errori e talvolta piuttosto inefficiente rispetto alle chiamate di costruzione e manipolandole .. @Nick S: È 'eval (q5) 'o' eval (e5) 'nel nostro esempio corrente –

1

Al giorno d'oggi è anche possibile utilizzare la funzione lazy_eval da lazyeval pacchetto.

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