You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何保存learnr教程的练习答案至.Rmd文件以用于评分?

解决方案:在learnr教程中本地保存用户答案到Rmd

嘿,这个需求完全可行!不用依赖Publish功能,咱们可以通过自定义Shiny逻辑,让用户把填写的答案直接保存为带内容的新Rmd文件,或者导出答案数据后你再合并到原教程里。下面是具体实现步骤:

核心思路

learnr内置了获取用户交互状态的函数,我们可以用它提取所有问题的答案,再把这些内容写入新的Rmd文件(避免覆盖原教程),或者让用户导出答案数据后你再合并。

方法一:添加“保存答案到Rmd”按钮

在你的learnr教程Rmd中,添加一个自定义的保存按钮和逻辑,用户完成所有问题后点击按钮就能生成带答案的新文件。

具体代码示例

在教程的最后一个章节(比如“完成与提交”)插入以下代码块:

library(shiny)
library(learnr)

# 自动设置工作目录为当前Rmd所在路径,避免文件读写路径错误
setwd(dirname(rmarkdown::metadata$path))

# 定义保存答案到新Rmd的函数
save_answers_to_rmd <- function() {
  # 获取所有用户输入的答案(包括代码题、选择题等)
  user_answers <- get_all_state()
  
  # 读取原教程的Rmd内容
  original_content <- readLines("your_tutorial.Rmd")  # 替换成你的教程文件名
  
  # 准备要添加的答案章节内容
  answer_section <- c(
    "\n---\n",
    "## 用户提交的答案\n",
    "### 所有问题的解答如下:\n"
  )
  
  # 遍历每个问题,格式化答案内容
  for (question_id in names(user_answers)) {
    # 区分代码题和选择题的答案格式
    if (!is.null(user_answers[[question_id]]$code)) {
      # 代码题:提取用户编写的代码
      answer_text <- paste0("```r\n", user_answers[[question_id]]$code, "\n```\n")
    } else if (!is.null(user_answers[[question_id]]$answer)) {
      # 选择题:提取用户选择的答案
      answer_text <- paste0("- 选择答案:", user_answers[[question_id]]$answer, "\n")
    } else {
      answer_text <- "- 无有效答案输入\n"
    }
    
    # 添加问题标题和答案到章节
    answer_section <- c(
      answer_section,
      paste0("#### 问题:", question_id, "\n"),
      answer_text
    )
  }
  
  # 合并原内容和答案,写入新的Rmd文件
  writeLines(c(original_content, answer_section), "your_tutorial_with_answers.Rmd")
  
  # 给用户弹出成功提示
  showNotification("✅ 答案已保存到 your_tutorial_with_answers.Rmd!", type = "message")
}

# 添加保存按钮
actionButton(
  inputId = "save_btn",
  label = "保存我的答案到新Rmd",
  onclick = "Shiny.setInputValue('save_trigger', Math.random());"
)

# 监听按钮点击,触发保存逻辑
observeEvent(input$save_trigger, {
  save_answers_to_rmd()
})

使用说明

  1. 把代码中的your_tutorial.Rmd替换成你实际的教程文件名。
  2. 用户点击“Run Document”完成所有问题后,点击“保存我的答案到新Rmd”按钮,就会在同一目录下生成带答案的新文件。
  3. 你拿到这个新Rmd后,直接打开运行就能看到用户填写的所有答案。

方法二:导出答案为RDS文件(更安全)

如果担心用户误操作覆盖原文件,可以让用户先导出答案为RDS数据文件,你再用脚本把答案合并到原教程里:

用户端导出代码

在教程中添加导出按钮:

actionButton("export_btn", "导出我的答案为RDS", onclick = "Shiny.setInputValue('export_trigger', Math.random());")

observeEvent(input$export_trigger, {
  user_answers <- get_all_state()
  saveRDS(user_answers, "user_answers.rds")
  showNotification("✅ 答案已导出为 user_answers.rds!", type = "message")
})

你端合并代码

拿到用户的user_answers.rds后,运行以下脚本生成带答案的Rmd:

library(learnr)

# 读取用户答案和原教程内容
user_answers <- readRDS("user_answers.rds")
original_content <- readLines("your_tutorial.Rmd")

# 生成答案章节(和方法一中的逻辑一致)
answer_section <- c(
  "\n---\n",
  "## 用户提交的答案\n",
  "### 所有问题的解答如下:\n"
)

for (question_id in names(user_answers)) {
  if (!is.null(user_answers[[question_id]]$code)) {
    answer_text <- paste0("```r\n", user_answers[[question_id]]$code, "\n```\n")
  } else if (!is.null(user_answers[[question_id]]$answer)) {
    answer_text <- paste0("- 选择答案:", user_answers[[question_id]]$answer, "\n")
  } else {
    answer_text <- "- 无有效答案输入\n"
  }
  
  answer_section <- c(
    answer_section,
    paste0("#### 问题:", question_id, "\n"),
    answer_text
  )
}

# 写入新文件
writeLines(c(original_content, answer_section), "your_tutorial_with_answers.Rmd")

注意事项

  • 确保用户运行教程时,工作目录是Rmd所在的文件夹(代码中已经用setwd自动处理了大部分情况)。
  • get_all_state()会获取所有交互式问题的状态,包括未完成的问题,你可以在代码中添加判断,只保存已完成的答案。
  • 如果你的教程有特殊类型的问题(比如填空题),可以调整answer_text的格式化逻辑来匹配。

内容的提问来源于stack exchange,提问作者Codrin Mironiuc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 13:02:53