繁体   English   中英

假设 R 中的 package::function() 列出脚本中所需的所有包

[英]List all the packages required in a script assuming package::function() in R

假设脚本中的所有非基础 R 函数都由package::function()调用。 因此,它在脚本运行期间没有任何完整的包加载。 假设我们有一个名为run.R的 R 脚本, run.R包含以下内容。

"data.table::fread(file)"

在这个例子中,脚本需要data.table包。 我正在寻找一个 R 函数,它读取这个外部run.R脚本会给安装所有请求的包的代码,即:

install.packages("data.table") 

关于现有功能或策略的任何想法?

您可以使用正则表达式尝试类似的操作:

f <- file("/path/to/here/file.R") # set up connection to file

file_lines <- readLines(con = f) # read file into list

close(f)

pckgs <- lapply(file_lines, function(l) { 
  if(grepl("::", l)){
    gsub(".*?([[:alnum:]\\.]+)::.*","\\1", l) 
  } else {
    return(NULL)
  }

})  
unique(unlist(pckgs))

我的工作假设包名只包含字母和数字。 如果不是这种情况,您可能需要更改正则表达式模式。

更新:将假设更改为包含. 根据data.table示例

使用正则表达式的其他解决方案也将匹配::如果它出现在注释或字符串文字中。 最好解析脚本并查找解析为pkg::fn操作的内容。 例如:

src <- "data.table::fread(file)"
# Use src <- readLines("source.R") in the real case, or parse the file directly

parsed <- parse(text = src)
parseData <- getParseData(parsed)
parseData$text[parseData$token == "SYMBOL_PACKAGE"]
#> [1] "data.table"

编辑添加:您可以将其放入一个函数中,以便在运行脚本之前安装必要的软件包。 例如,如果这些行在~/temp/run.R

file <- "not::a::package"
data.table::fread(file)
foobar::notafunction()

然后你会得到这些结果:

installThenSource <- function(file, ...) {
  parsed <- parse(file)
  parseData <- getParseData(parsed)
  packages <- unique(parseData$text[parseData$token == "SYMBOL_PACKAGE"])
  for (p in packages) {
    if (!requireNamespace(p, quietly = TRUE)) {
      message("Installing ", p)
      install.packages(p)
      if (!requireNamespace(p, quietly = TRUE))
        stop("Install of ", p, " failed.")
    } else
      message("Package ", p, " already installed.")
  }
  source(file, ...)
}

installThenSource("~/temp/run.R")
#> Package data.table already installed.
#> Installing foobar
#> Warning: package 'foobar' is not available (for R version 3.6.1)
#> Error in installThenSource("~/temp/run.R"): Install of foobar failed.

这是一个查找类似package::function字符串的package::function

findPackages <- function(file){
  txt <- readLines(file)
  inx <- grep('::', txt)
  txt <- txt[inx]
  m <- regexpr('[[:alnum:]]+::', txt)
  pkg <- regmatches(txt, m)
  unique(sub('::', '', pkg))
}

这个 Ubuntu bash 命令获取工作目录中所有带有::文件*.R

fls <- system2('grep', args = c('-l', '::', '*.R'), stdout = TRUE)

现在将该函数应用到一个调用类似函数的文件。

findPackages(fls[1])

以及使用 bash 命令找到的所有此类文件。

pkgs <- lapply(fls, findPackages)
unique(unlist(pkgs))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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