Evaluar la expresión dada como una cadena
Pregunta
Tengo curiosidad por saber si R puede utilizar su función de eval()
para realizar cálculos proporcionados por ejemplo, una cadena.
Este es un caso común:
eval("5+5")
Sin embargo, en lugar de 10 me sale:
[1] "5+5"
Cualquier solución?
Solución
La función eval()
evalúa una expresión, pero "5+5"
es una cadena, no una expresión. Utilice parse()
con text=<string>
cambiar la cadena en una expresión:
> eval(parse(text="5+5"))
[1] 10
> class("5+5")
[1] "character"
> class(parse(text="5+5"))
[1] "expression"
Calling eval()
invoca muchos comportamientos, algunos no son inmediatamente obvias:
> 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 .
Otros consejos
Puede utilizar la función parse()
para convertir los caracteres en una expresión. Es necesario especificar que la entrada es de texto, ya que de análisis espera un archivo por defecto:
eval(parse(text="5+5"))
Lo siento, pero no entiendo por qué muchas personas llegan a pensar una cadena era algo que podría ser evaluada. Debe cambiar su forma de pensar, de verdad. Olvídese de todas las conexiones entre las cuerdas de un lado y expresiones, las llamadas, la evaluación en el otro lado.
El (posiblemente) única conexión es a través de parse(text = ....)
y todos los buenos programadores R debe saber que esto no suele ser un medio eficaz o segura para construir expresiones (o llamadas). En lugar de aprender más sobre substitute()
, quote()
, y, posiblemente, el poder de utilizar 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, aquí es un ejemplo (en los comentarios, no hay ningún formato agradable):
q5 <- quote(5+5)
str(q5)
# language 5 + 5
e5 <- expression(5+5)
str(e5)
# expression(5 + 5)
y si más experiencia usted aprenderá que q5
es un "call"
mientras que e5
es un "expression"
, e incluso que e5[[1]]
es idéntica a q5
:
identical(q5, e5[[1]])
# [1] TRUE
Como alternativa, puede utilizar evals
de mi paquete pander
para capturar la salida y todas las advertencias, errores y otros mensajes junto con los resultados primas:
> 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"
Hoy en día también se puede utilizar la función de lazy_eval
paquete lazyeval
.
> lazyeval::lazy_eval("5+5")
[1] 10
usando mismo modo rlang
:
eval(parse_expr("5+5"))