如何可靠判断函数所在文档是RMarkdown还是Quarto?
可靠判断当前文档是Quarto还是RMarkdown的方法
要实现根据文档类型切换函数行为,推荐按优先级从高到低的顺序结合多种检测策略,确保在渲染时、编辑时都能准确判断:
核心检测思路
- 优先使用knitr运行时标志:渲染阶段knitr会直接提供文档类型信息,这是最可靠的方式
- 解析YAML元数据:Quarto和RMarkdown的YAML配置有明确差异
- 编辑器上下文检测:在RStudio中可通过文件扩展名判断
- 文档内容特征兜底:识别两种格式特有的语法元素
完善后的检测函数
#' 检测当前文档是否为Quarto文档 #' #' @param text 文档文本(可选,当无法获取运行时或编辑器信息时使用) #' @param default 所有检测策略失败时返回的默认值 #' @return 逻辑值:TRUE=Quarto文档,FALSE=RMarkdown文档 #' @noRd detect_quarto_document <- function(text = NULL, default = FALSE) { # 策略1:优先用knitr内置函数(knitr 1.42+版本支持,最可靠) if (requireNamespace("knitr", quietly = TRUE)) { if (exists("is_quarto", envir = asNamespace("knitr"))) { return(knitr::is_quarto()) } # 兼容旧版knitr:通过pandoc输出格式或文档格式判断 quarto_formats <- c("quarto-html", "quarto-pdf", "quarto-docx", "quarto-pptx") if (knitr::opts_knit$get("rmarkdown.pandoc.to") %in% quarto_formats) { return(TRUE) } } # 策略2:解析YAML元数据 if (!is.null(text)) { lines <- strsplit(text, "\n", fixed = TRUE)[[1]] # 检查是否有YAML头部 yaml_start <- which(grepl("^---$", lines))[1] yaml_end <- which(grepl("^---$", lines))[2] if (!is.na(yaml_start) && !is.na(yaml_end) && yaml_start < yaml_end) { yaml_content <- tryCatch( yaml::yaml.load(paste(lines[yaml_start:yaml_end], collapse = "\n")), error = function(e) NULL ) if (!is.null(yaml_content)) { # Quarto特有YAML字段:format(而非RMarkdown的output)、quarto-required、shortcodes if (!is.null(yaml_content$format) || !is.null(yaml_content[["quarto-required"]]) || !is.null(yaml_content$shortcodes)) { return(TRUE) } # RMarkdown特有YAML字段:output if (!is.null(yaml_content$output)) { return(FALSE) } } } } # 策略3:RStudio编辑器上下文检测(仅在RStudio中生效) if (requireNamespace("rstudioapi", quietly = TRUE) && rstudioapi::isAvailable()) { ctx <- tryCatch(rstudioapi::getSourceEditorContext(), error = function(e) NULL) if (!is.null(ctx) && !is.null(ctx$path)) { if (grepl("\\.qmd$", ctx$path, ignore.case = TRUE)) { return(TRUE) } else if (grepl("\\.rmd$", ctx$path, ignore.case = TRUE)) { return(FALSE) } } } # 策略4:文档内容特征兜底(检测Quarto特有的短代码或RMarkdown特有的代码块) if (!is.null(text)) { # 检测Quarto短代码(如 {{< include >}})或RMarkdown的内嵌代码(如 `r `) if (grepl("{{<\\s+.*\\s+>}}", text)) { return(TRUE) } if (grepl("`r\\s+", text)) { return(FALSE) } } return(default) }
适配你的预处理函数示例
基于上述检测结果,实现模板替换逻辑:
preprocess_document <- function(text) { is_quarto <- detect_quarto_document(text) if (is_quarto) { # Quarto中替换{{foo}}为{{foo_bar}} gsub("\\{\\{([a-zA-Z0-9_]+)\\}\\}", "{{\\1_bar}}", text) } else { # RMarkdown中替换{{foo}}为`r foo_bar` gsub("\\{\\{([a-zA-Z0-9_]+)\\}\\}", "`r \\1_bar`", text) } }
关键说明
- knitr运行时检测:
knitr::is_quarto()是最权威的判断方式(knitr 1.42及以上版本支持),渲染时直接获取文档类型,完全不需要依赖文本或扩展名 - YAML检测:Quarto用
format定义输出格式,RMarkdown用output,这是两者最核心的配置差异 - 编辑器上下文:仅作为编辑时的辅助检测,渲染阶段不依赖
- 内容兜底:当其他策略失效时,通过语法特征判断,适合无YAML的简单文档
内容的提问来源于stack exchange,提问作者vorpal
相关产品推荐
相关产品推荐

