R 中更好的字符串插值

Better string interpolation in R

我需要在 R 中构建长命令行并将它们传递给 system()。我发现使用 paste0/paste 函数非常不方便,甚至 sprintf 函数来构建每个命令行。有没有更简单的方法:

而不是这个难以阅读和太多的引用:

cmd <- paste("command", "-a", line$elem1, "-b", line$elem3, "-f", df$Colum5[4])

或:

cmd <- sprintf("command -a %s -b %s -f %s", line$elem1, line$elem3, df$Colum5[4])

我可以要这个吗:

cmd <- buildcommand("command -a %line$elem1 -b %line$elem3 -f %df$Colum5[4]")

这与您的要求非常接近。当任何函数 f 以 fn$ 开头时,即 fn$f,将执行字符插值,将 ... 替换为 运行 的结果 ... 作为 R 表达式。

library(gsubfn)
cmd <- fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")

这是一个独立的可重现示例:

library(gsubfn)

# test inputs
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)

fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## [1] "command -a 10 -b 30 -f 4"

系统

因为可以使用任何函数,所以我们可以像这样直接对 system 调用进行操作。我们在这里使用 echo 使其可执行,但可以使用任何命令。

exitcode <- fn$system("echo -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## -a 10 -b 30 -f 4

变化

这个变体也可以。 fn$f 还执行用变量 whatever 的值替换 $whatever。有关详细信息,请参阅 ?fn

with(line, fn$identity("command -a $elem1 -b $elem3 -f `df$Colum5[4]`"))
## [1] "command -a 10 -b 30 -f 4"

在 1.1.0 版本(CRAN 于 2016-08-19 发布)中,stringr 包获得了一个字符串插值函数 str_interp(),它是 的替代方法。

# sample data
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)

# do the string interpolation
stringr::str_interp("command -a ${line$elem1} -b ${line$elem3} -f ${df$Colum5[4]}")
#[1] "command -a 10 -b 30 -f 4"

另一种选择是使用 https://github.com/edwindj/whisker 中的 whisker.render,它是 R 中的 {{Mustache}} 实现。用法示例:

require(dplyr); require(whisker)

bedFile="test.bed"
whisker.render("processing {{bedFile}}") %>% print

有关 tidyverse 解决方案,请参阅 https://github.com/tidyverse/glue。例子

name="Foo Bar"
glue::glue("How do you do, {name}?")
library(GetoptLong)

str = qq("region = (@{region[1]}, @{region[2]}), value = @{value}, name = '@{name}'")
cat(str)

qqcat("region = (@{region[1]}, @{region[2]}), value = @{value}, name = '@{name}'")

https://cran.r-project.org/web/packages/GetoptLong/vignettes/variable_interpolation.html

不是真正的字符串插值解决方案,但仍然是解决该问题的一个很好的选择是使用 processx 包而不是 system() 然后你不需要引用任何东西。