简体   繁体   中英

Passing a character string as a parameter name/value pair into a R function

I would like to use a character string (s) in order to pass it to a function as a name/value pair for a parameter. Test1 shows what I would like to achieve. In Test2, R does not call getInfo(PHONE_NUMBER = 123456) but, based on paramter order, uses getInfo(FULL_NAME = "PHONE_NUMBER = 123456"). How could I change that?

The string could also contain various paramters I would like to parse, eg, "PHONE_NUMBER = 123456, ZIP = 1234"


s <- "PHONE_NUMBER = 123456"
getInfo <- function(FULL_NAME = "", FIRST_NAME = "", LAST_NAME = "", 
  ZIP = "", PHONE_NUMBER = "") {
  l <- as.list(match.call())
  myNames <- names(unlist(l[c(2, length(l))]))
  print(myNames)
  myValues <- unlist(l[c(2, length(l))])
  print(myValues)
  searchString <- paste(myNames, myValues, sep = "=", collapse = "&")
  searchString <- paste0("search?PHONE_NUMBER=", searchString)
}
# Test 1: Setting the paramter manually
getInfo(PHONE_NUMBER = 123456)
#> [1] "PHONE_NUMBER" "PHONE_NUMBER"
#> PHONE_NUMBER PHONE_NUMBER 
#>       123456       123456
# Test2 : Attempt to pass string as name/value fails; R uses the complete string as the first paramter (FULL_NAME = "PHONE_NUMBER = 123456") instead
getInfo(s)
#> [1] "FULL_NAME" "FULL_NAME"
#> $FULL_NAME
#> s
#> 
#> $FULL_NAME
#> s

We can create an environment and create variables inside the environment. Then convert the environment into list and pass the list of variables as arguments into the function.

To learn more on environments in R, refer this link .

Without string s

getInfo(PHONE_NUMBER = 123456)
do.call("getInfo", list(PHONE_NUMBER = 123456))
# [1] "PHONE_NUMBER" "PHONE_NUMBER"
# PHONE_NUMBER PHONE_NUMBER 
# 123456       123456

With string s containing single argument

s <- "PHONE_NUMBER = 123456"
myenv <- new.env()  # create new environment
eval(parse(text = s), envir = myenv)  # create variables inside environment using string s
ls(name = myenv)  # list all variables inside the environment
# [1] "PHONE_NUMBER"
myenv$PHONE_NUMBER
# [1] 123456
do.call("getInfo", as.list.environment(myenv))  # call the function by passing the arguments which is obtained by converting environment into list
# [1] "PHONE_NUMBER" "PHONE_NUMBER"
# PHONE_NUMBER PHONE_NUMBER 
# 123456       123456 

With string s containing multiple arguments - will work for single or multiple arguments

s <- "PHONE_NUMBER = 123456, ZIP = 1234"
s <- unlist(strsplit(s, split = ",", fixed = TRUE))  # split string s using comma separator
s
# [1] "PHONE_NUMBER = 123456" " ZIP = 1234" 
myenv <- new.env()
eval(parse(text = s), envir = myenv)
ls(name = myenv)
# [1] "PHONE_NUMBER" "ZIP" 
do.call("getInfo", as.list.environment(myenv))
# [1] "ZIP"          "PHONE_NUMBER"
# ZIP PHONE_NUMBER 
# 1234       123456 

@Sathish 's answer above is nice but does not work with more complex arguments. For example, when one wants to pass a vector (which contains commas):

> s <- "PHONE_NUMBER = 123456, ZIP = c(1234, 4321)"
> s <- unlist(strsplit(s, split = ",", fixed = TRUE))
> myenv <- new.env()
> eval(parse(text = s), envir = myenv)
Error in parse(text = s) : <text>:3:2: unexpected numeric constant
2:  ZIP = c(1234
3:  4321

There's a much better and more flexible way, using R's machinery for the purpose:

> s <- "PHONE_NUMBER = 123456, ZIP = c(1234, 4321)"
> getArgs <- function(...) return(list(...))
> pars <- try(eval(parse(text=sprintf("getArgs(%s)", s))), silent=TRUE)
> pars
$PHONE_NUMBER
[1] 123456

$ZIP
[1] 1234 4321

It even works when s is not syntactically correct -- in that case pars will contain an object of class "try-error" .

Nevertheless, there's an important security risk in the use of eval() . To avoid unpleasant surprises (=user executing arbitrary code), you might want to disallow and remove any ";" or newline characters in s :

s <- gsub(";|\n", "", s)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM