Johannes Graumann
2013-Jan-28 07:29 UTC
[R] parse/eval and character encoded expressions: How to deal with non-encoding strings?
Hi, I am intending to save a path-describing character object in a slot of a class I'm working on. In order to have the option to use "system.file" etc in such string-saved path definitions, I wrote this ExpressionEvaluator <- function(x){ x <- tryCatch( expr=base::parse(text=x), error = function(e){return(as.expression(x))}, finally=TRUE) return(x) } This produces> ExpressionEvaluator("system.file(\"INDEX\")")expression(system.file("INDEX"))> eval(ExpressionEvaluator("system.file(\"INDEX\")"))[1] "/usr/lib/R/library/base/INDEX" Which is what I want. However,> eval(ExpressionEvaluator("Test"))Error in eval(expr, envir, enclos) : object 'Test' not found prevents me from general usage (also in cases where "x" does NOT encode an expression). I don't understand why it is that> base::parse(text="Test")will return [1] expression(Test) while> as.expression("Test")produces [1] expression("Test") which would work with the eval call. Can anyone point out to me how to solve this generally? How can I feed the function a character object and get back an eval-able expression independent of whether there was an expression "encoded" in the input or not. Thank you for any hints. Sincerely, Joh
William Dunlap
2013-Jan-28 16:14 UTC
[R] parse/eval and character encoded expressions: How to deal with non-encoding strings?
Instead of saving a string that can be parsed into a language object (and later evaluated), I would just save something that that could be evaluated directly. Note that a literal like "MyFile" or 3.14 evaluates to itself so you can save a literal string or a language object and use eval() on either. Unless you do this there is no good way to know if "TestDir/TestFile*.txt" means to do some multiplication and division or to use a glob pattern to find a group of files. E.g., makeFoo <- function(file, ...) { structure(c(...), fileExpr=substitute(file), class="Foo") } getFileFoo <- function(FooObject) { eval(attr(FooObject, "fileExpr")) } used as > z <- makeFoo(system.file(package="fpp", "DESCRIPTION"), 1, 2, 3) > z [1] 1 2 3 attr(,"fileExpr") system.file(package = "fpp", "DESCRIPTION") attr(,"class") [1] "Foo" > getFileFoo(z) [1] "C:/Program Files/R/R-2.15.2/library/fpp/DESCRIPTION" or > z <- makeFoo("C:/Temp/File.txt", 1, 2, 3) > z [1] 1 2 3 attr(,"fileExpr") [1] "C:/Temp/File.txt" attr(,"class") [1] "Foo" > getFileFoo(z) [1] "C:/Temp/File.txt" One thing you might worry about is in which environment the language object is evaluated (the envir= argument to eval()). If you embed your object in a formula then environment(formula) tells you where to evaluate it. If the formula syntax is distracting then you can attach an attribribute called ".Environment" to your object that environment(object) will retrieve. E.g., makeFooEnv <- function(file, ..., envir = parent.frame()) { fileExpr <- structure(substitute(file), .Environment = envir) structure(c(...), fileExpr = fileExpr, class="Foo") } getFileFoo <- function(FooObject) { fileExpr <- attr(FooObject, "fileExpr") eval(fileExpr, envir=environment(fileExpr)) } used as > fooObjs <- lapply(1:3, function(i)makeFooEnv(paste0("File",i,".txt"), i^2)) > fooObjs[[2]] [1] 4 attr(,"fileExpr") paste0("File", i, ".txt") attr(,"fileExpr")attr(,".Environment") <environment: 0x000000000b7f8998> attr(,"class") [1] "Foo" > > i <- 17 > getFileFoo(fooObjs[[2]]) # Note that eval gets value of i as 2, not 17 [1] "File2.txt" Bill Dunlap Spotfire, TIBCO Software wdunlap tibco.com> -----Original Message----- > From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf > Of Johannes Graumann > Sent: Sunday, January 27, 2013 11:29 PM > To: r-help at stat.math.ethz.ch > Subject: [R] parse/eval and character encoded expressions: How to deal with non- > encoding strings? > > Hi, > > I am intending to save a path-describing character object in a slot of a > class I'm working on. In order to have the option to use "system.file" etc > in such string-saved path definitions, I wrote this > > ExpressionEvaluator <- function(x){ > x <- tryCatch( > expr=base::parse(text=x), > error = function(e){return(as.expression(x))}, > finally=TRUE) > return(x) > } > > This produces > > > ExpressionEvaluator("system.file(\"INDEX\")") > expression(system.file("INDEX")) > > eval(ExpressionEvaluator("system.file(\"INDEX\")")) > [1] "/usr/lib/R/library/base/INDEX" > > Which is what I want. However, > > > eval(ExpressionEvaluator("Test")) > Error in eval(expr, envir, enclos) : object 'Test' not found > > prevents me from general usage (also in cases where "x" does NOT encode an > expression). > > I don't understand why it is that > > base::parse(text="Test") > will return > [1] expression(Test) > while > > as.expression("Test") > produces > [1] expression("Test") > which would work with the eval call. > > Can anyone point out to me how to solve this generally? How can I feed the > function a character object and get back an eval-able expression independent > of whether there was an expression "encoded" in the input or not. > > Thank you for any hints. > > Sincerely, Joh > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.