1

glue()用来格式化字符串。理想情况下,我想给用户提供他自己的、可能复杂的格式模式的选项。这些通常作为 yaml 配置文件的一部分分发,该文件还包含许多其他设置。

library(glue)
df <- tibble(a = c(70,80,90,4,5), conversionunit = c(60,60,60,1,1))
pattern <- "{a/conversionunit} minutes" # loaded from user's config file
df <- df %>% mutate(output = glue(pattern))

# more complex alternative
pattern <- "{round(a/conversionunit, digits=2)} minutes" # loaded from user's config file
df <- df %>% mutate(output = glue(pattern))

glue但是,由于语句可能执行任意代码,因此存在安全风险。下面的例子当然是良性的。风险之所以存在,是因为用户可能会在没有详细研究的情况下下载和使用复杂的配置文件,并且不良行为者可能会分发邪恶的配置文件。

pattern <- "{shell('echo 1', intern = TRUE)} {a}"
df <- df %>% mutate(output = glue(pattern))

但是我知道glue_safe这比我想要的更严格。理想情况下,我想提供允许的功能列表

safe_fun <- list(`*` = `*`, `/` = `/`, "round" = round) %>% as.environment() # etc

并只允许使用那些指定的。有没有办法做到这一点?

4

2 回答 2

2

定义保存数据和函数的环境并将其父级设置为emptyenv().

library(glue)
library(tibble) # lst

safe_fun <- lst(`*`, `/`, round)
safe_env <- list2env(c(df, safe_fun), parent = emptyenv())

# test 1
glue("{a/conversionunit} minutes", .envir = safe_env)
## 1.16666666666667 minutes
## 1.33333333333333 minutes
## 1.5 minutes
## 4 minutes
## 5 minutes

# test 2
glue("{sqrt(a)/conversionunit} minutes", .envir = safe_env)
## Error in sqrt(a) : could not find function "sqrt"
于 2021-02-12T18:58:55.280 回答
1

基于这个先前的答案

library(glue)
library(dplyr)

df <- tibble(a = c(70,80,90,4,5), conversionunit = c(60,60,60,1,1))

allowed <- c("/")

# Create new empty environment
safe_env <- new.env(parent = emptyenv())

# assign allowed functions & objects
lapply(allowed,function(f) assign(f,get(f),safe_env))
list2env(df,safe_env)

pattern <- "{a/conversionunit} minutes" # loaded from user's config file

df %>% mutate(output = glue(pattern,.envir=safe_env))
#> # A tibble: 5 x 3
#>       a conversionunit output                  
#>   <dbl>          <dbl> <glue>                  
#> 1    70             60 1.16666666666667 minutes
#> 2    80             60 1.33333333333333 minutes
#> 3    90             60 1.5 minutes             
#> 4     4              1 4 minutes               
#> 5     5              1 5 minutes


于 2021-02-12T18:05:56.843 回答