我将子文档视为可能的解决方案,但我不想在父文档中包含整个子文档。我希望能够扫描子文档以获取相关信息,然后将该信息块提取到父文档中。
例如,如果我要制作有关在我选择的任何位置度假的可重复报告,我想创建一个子文档,其中包含我可以有选择地从中提取信息的不同部分,例如:海滩度假技巧、登山技巧、巡航技巧。 .. 因此,如果我想生成一份有关新西兰的报告,我想在我的子文档中搜索标题“海滩度假提示”,并将其拉入我的父文档中。但如果我要制作有关尼泊尔的报告,我不想包含有关海滩的文本,因此我想跳过子文档的这一部分。
有什么办法可以做到这一点吗?谢谢!
我已经研究了 readLines 和子文档,但我似乎找不到完全符合我正在寻找的代码。这篇文章How to source R Markdown file like `source('myfile.r')`? 有一些我认为可能有帮助的功能,但我正在努力寻找直接的解决方案。
编辑:我弄清楚了如何使用“readLines”函数从子文档中读取特定行并将它们包含在父文档中。我可能会使用 if/else 根据我正在制作的报告类型从子文档中提取我想要的确切行。但我想知道是否有一种方法可以在子文档中搜索标题,而不是使用行号。
子文档:
# Header
Text blah blah.
Blah blah.
Blah.
父文件:
{r, echo=FALSE, results='asis'}
cat(readLines('child.Rmd')[c(13:15)], sep = '\n')
在父文档中是否有一种简洁的方式来编写我想要子文档中“# Header”下的所有文本?谢谢!
如果您想从 Rmd 文件中提取特定块,您可以使用
knitr::purl
。
我将从“hello world”rmarkdown 文档开始:
---
title: Hello world
params:
something: "hello"
---
Intro paragraph.
```{r block1, echo = FALSE}
library(dplyr)
# do something here
out1 <- mtcars %>%
group_by(cyl) %>%
summarize(disp = sum(disp))
```
Another paragraph.
```{r block2}
out2 <- iris %>%
count(Species)
out2
```
Something else?
```{r}
head(mtcars)
```
现在让我们提取代码块:
tf <- tempfile()
knitr::purl("quux.Rmd", output=tf)
# processing file: quux.Rmd
#
# output file: /home/r2/tmp/RtmpgcG3Ae/file4aad8216b2ef2
# [1] "/home/r2/tmp/RtmpgcG3Ae/file4aad8216b2ef2"
txt <- readLines(tf)
head(txt)
# [1] "params <-"
# [2] "list(something = \"hello\")"
# [3] ""
# [4] "## ----block1, echo = FALSE------------------------------------------------------------------------------------------------------------------------------------"
# [5] "library(dplyr)"
# [6] "# do something here"
从这里开始,如果我们想按块分割,我们可以这样做:
blocks <- split(txt, cumsum(grepl("^## ----([^-].*[^-])?-+$", txt)))
blockheaders <- gsub("(^## ----|-+$)", "", lines1) |>
strsplit(",") |>
lapply(function(z) {
if (!length(z)) list("unk", "list()") else {
list(z[1], paste0("list(", paste(z[-1], collapse = ", "), ")"))
}
})
str(blockheaders)
# List of 3
# $ 1:List of 2
# ..$ : chr "block1"
# ..$ : chr "list( echo = FALSE)"
# $ 2:List of 2
# ..$ : chr "block-2"
# ..$ : chr "list()"
# $ 3:List of 2
# ..$ : chr "unk"
# ..$ : chr "list()"
names(blocks) <- c("params", make.unique(sapply(blockheaders, `[[`, 1)))
str(blocks)
# List of 4
# $ params : chr [1:3] "params <-" "list(something = \"hello\")" ""
# $ block1 : chr [1:8] "## ----block1, echo = FALSE------------------------------------------------------------------------------------"| __truncated__ "library(dplyr)" "# do something here" "out1 <- mtcars %>%
" ...
# $ block-2: chr [1:6] "## ----block-2-------------------------------------------------------------------------------------------------"| __truncated__ "out2 <- iris %>%
" " count(Species)" "out2" ...
# $ unk : chr [1:3] "## ------------------------------------------------------------------------------------------------------------"| __truncated__ "head(mtcars)" ""
您可以根据位置、块名称或在代码中查找模式来选择要使用的块。我建议,如果您想要明确访问特定块,请使块名称唯一,和/或在每个块中做出清晰的可解析注释,例如
```{r}
###{Houston}###
mtcars %>% count(cyl)
```
如果需要它们,您可以解析并使用每个块的参数,
params <- lapply(setNames(blockheaders, names(blocks)[-1]), `[[`, 2)
str(params)
# List of 3
# $ block1 : chr "list( echo = FALSE)"
# $ block-2: chr "list()"
# $ unk : chr "list()"
备注:
我认为用于块确定的正则表达式足以处理块名称,但我还没有充分检查法律要求以了解这种模式是否万无一失。如果你的名字倾向于字母数字,那么我想你会没事的。
根据需要,您可以解析块内容和/或(如果您需要它们)块参数,没有太大困难,尽管您需要确保满足所有先决条件(即可以定义的对象)在之前的区块中)。
## header/yaml params
eval(parse(text = blocks[[1]][-1]))
# $something
# [1] "hello"
## block params
eval(parse(text = params$block1))
# $echo
# [1] FALSE
eval(parse(text = params$`block-2`))
# list()
## parse block contents
eval(parse(text = blocks$unk))
# mpg cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
# Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1