我可以通过有条件地从另一个 Rmd 文件中仅提取一些文本块来自定义 R Markdown 报告吗?

问题描述 投票:0回答:1

我将子文档视为可能的解决方案,但我不想在父文档中包含整个子文档。我希望能够扫描子文档以获取相关信息,然后将该信息块提取到父文档中。

例如,如果我要制作有关在我选择的任何位置度假的可重复报告,我想创建一个子文档,其中包含我可以有选择地从中提取信息的不同部分,例如:海滩度假技巧、登山技巧、巡航技巧。 .. 因此,如果我想生成一份有关新西兰的报告,我想在我的子文档中搜索标题“海滩度假提示”,并将其拉入我的父文档中。但如果我要制作有关尼泊尔的报告,我不想包含有关海滩的文本,因此我想跳过子文档的这一部分。

有什么办法可以做到这一点吗?谢谢!

我已经研究了 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”下的所有文本?谢谢!

r r-markdown knitr
1个回答
0
投票

如果您想从 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
    
© www.soinside.com 2019 - 2024. All rights reserved.