用 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 绝对是你可信赖的靠谱厮。
最后,我要隆重感谢张敬信老师提供的思路和全程技术指导。