Welcome to R Square

用 R 批量生成制式化的 Word 文档

楚新元 / 2021-09-24


更新 2025-09-12

本文模板进行了更新,对公文抬头(Salutation)、首行(First Paragraph)和成文日期(Signatrue Date)进行了定制;R Markdown 代码部分对公文抬头前的空行问题、公文抬头引入、成文日期引入作了调整,规范了部分变量名;对自动批量生成复工证明代码进行了优化调整和详细注释。

类似这样的批量生成简历、准考证、证明之类的 Word 文档,MS Office 玩家一般的做法是利用邮件合并功能或者 VBA 实现,对于 R 玩家来说必然是用 R 实现了,暂时没有发现比我这个方法更优雅的方法了。这里以批量生成复工证明 Word 文档为例。

安装公文字体

为了保证最终生成的 Word 文档字体符合公文要求,首先你需要在自己的电脑上安装必要的公文字体,如方正小标宋_GBK(有的单位是方正小标宋)和仿宋_GB2312等。安装公文字体不是本文重点,此处从略。

定义一个 Word 模板

最好是先通过 R Markdown 生成一个 Word 文档,然后在此基础上修改,当然如果通过 R Markdown 默认生成的 Word 文档要是能满足您的要求,不修改也可以,为了充分挖掘 R Markdown 的潜能,自然是各种个性化的修改了(注意:设置模板不要用开始菜单下的那一堆工具按钮,而要在样式和格式里修改。为了保证普适性,建议在 Microsoft Word 下设置模板格式。)。这里是我修改好的一个符合公文要求的模板供参考。

R Markdown 文档参数化设置

主要是把每份复工证明 Word 文档的不同的地方用参数来表示,比如姓名、身份证和家庭住址,就像填空题一样,方便批量生成。参数化设置后的 R Markdown 文档示例代码如下:

---
title: "复工证明"
output: 
  officedown::rdocx_document:
    # 引用模板用来控制最终生成的 Word 的格式
    reference_docx: template.docx
    page_margins:
      top: 1.458     # 页边距(上37)
      bottom: 1.380  # 页边距(下35)
      left: 1.063    # 页边距(左27)
      right: 1.063   # 页边距(右27)
      gutter: 0.00   # 设置装订线
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```

```{r}
# 处理公文抬头前的空行问题
officer::ftext("")
officer::fp_par(text.align = "center")
```

```{r}
# 公文抬头或称呼,格式引用模板文件的“称呼(Salutation)”
salutation = "西域天竺国:"
paragraph_salutation = officer::fpar(
  officer::ftext(salutation), 
  fp_p = officer::fp_par_lite(
    # 未定义参数会继承默认设置
    word_style = "Salutation"
  )
)
officer::block_list(paragraph_salutation)
```

兹有大唐天子圣谕,`r name`同志,身份证`r ID`,系我天朝`r address`子民,根据我天朝复工要求,该同志在防疫管控期间需要保护唐僧赴西天大雷音寺取经,在满足疫情防控要求的情况下请贵国予以放行为盼。

特此说明。

```{r}
# 附件和正文之间空一行
officer::ftext("")
```

```{r}
# 引入附件,格式与正文部分相同,无需独设置
officer::ftext(paste0("附件:", name, "同志身份证复印件"))
```

```{r}
officer::ftext("")  # 落款前空第一行
```

```{r}
officer::ftext("")  # 落款前空第二行
```

```{r}
officer::ftext("")  # 落款前空第三行
```

```{r}
# 发文机关署名
signature = "大唐天子李世民"

# 使用当前日期生成中文格式的成文日期,例如 "2025年9月9日"
date = as.Date(Sys.Date())
year  = as.integer(format(date, '%Y'))
month = as.integer(format(date, '%m'))
day = as.integer(format(date, '%d'))
date_signature = paste0(year, "年", month, "月", day, "日")

# 计算成文日期前面的空格
date_signature_width = systemfonts::string_width(
  strings = date_signature, 
  family = "FangSong_GB2312",
  size = 16
)
date_signature_space = (27 * 16 - 6 * 16 - date_signature_width) / 8

# 计算发文单位前面的空格
signature_width = systemfonts::string_width(
  strings = signature, 
  family = "FangSong_GB2312",
  size = 16
)
signature_space = floor(
  date_signature_space + 
  ((date_signature_width - signature_width) / 2) / 8
)

# 引入发文机关署名,位置根据成文日期的位置确定 
officer::ftext(
  paste0(strrep(" ", signature_space), signature)
)
```

```{r}
# 引入成文日期,格式引用模板文件的 “Signature Date”
paragraph_date_signature = officer::fpar(
  officer::ftext(date_signature), 
  fp_p = officer::fp_par_lite(
    word_style = "Signature Date"
  )
)
officer::block_list(paragraph_date_signature)
```

收集数据,批量生成 Word 文档

先把上面的参数化的 R Markdown 文档保存,例如命名为 report.Rmd,然后将 template.docx 文件和 report.Rmd 文件放在同一个 R 项目下,我们现在只需要收集所有需要开证明人的姓名、身份证和家庭住址信息(数据可以放在代码里,为了便于管理,最好存放在文件中然后读进来),然后批量渲染这个 report.Rmd 文档即可。源代码如下:

#'
#' 自动批量生成复工证明
#'
#' 本脚本根据预设参数渲染 R Markdown 报告,生成公文格式的 Word 文档。
#' 结果文档按标题和标题归档至 `./result/` 目录下。
#'
#' @author 楚新元
#' @date 2025-09-11
#' 
#' @inputs
#'   - `name`: 姓名(全局变量)
#'   - `ID`: 身份证号(全局变量)
#'   - `address`: 住址(全局变量))
#' @outputs
#'   - 输出 Word 文档到 ./result/<name>复工证明.docx
#'
#' @section 使用说明:
#'   1. 根据实际公文需要修改以下参数
#'   2. 保存后运行本脚本,将自动批量生成复工证明
#'
#' @section 注意事项:
#'   - 公文模板 `template.docx` 只能通过 MS Word 修改样式
#'   - 所有字符串参数请使用 UTF-8 编码,确保中文正常显示
#'

# ------------------------------
# 用户可修改参数区
# ------------------------------

name    = c("孙悟空", "猪悟能", "沙悟净")
ID      = c("001", "002", "003")
address = c("花果山水帘洞", "高老庄", "流沙河")

# ------------------------------
# 执行报告生成流程
# ------------------------------

# 构建归档路径:./result/<name>复工证明.docx
if (!dir.exists("result")) dir.create("result")

# 编写函数
gendocx = \(name, ID, address) {
  rmarkdown::render(
    input = "report.Rmd", 
    output_file = file.path(
      "result", 
      paste0(name, "复工证明", ".docx")
    )
  )
}

# 批量生成
data = data.frame(name, ID, address)
purrr::pwalk(data, gendocx)

运行上述代码后就会生成 3 个包含姓名命名的 Word 文档,如“孙悟空复工证明.docx”。需要批量生成复工证明的如果只有这 3 个人,我也就懒得去写代码了,但是随着需要开证明人数的增加你一定会发现用代码生成才是正道,您仅仅需要维护一份包含姓名、身份证和家庭住址的文档即可,重复性的工作交给计算机。另外代码生成的结果您认为还需要再复核一遍吗?R 绝对是你可信赖的靠谱厮。

最后,我要隆重感谢张敬信老师提供的思路和全程技术指导。