楚新元 | All in R

Welcome to R Square

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

楚新元 / 2021-09-24


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

安装公文字体

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

定义一个 Word 模板

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

模板下载:https://cxy.rbind.io/source/template.docx

R Markdown 文档参数化设置

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

---
title: "复工证明"
author: '`r ftext("")`'  # 标题下面空一行
output: 
  officedown::rdocx_document:
    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 name`同志,身份证`r ID`,系我天朝`r address`子民,根据我天朝复工要求,该同志在防疫管控期间需要保护唐僧赴西天大雷音寺取经,在满足疫情防控要求的情况下请贵国予以放行为盼。

特此说明。

```{r echo=FALSE}
ftext("")  # 附件和中文之间空1行
```

附件:`r name`同志身份证复印件

```{r echo=FALSE}
ftext("")  # 这里落款前空第1行
```

```{r echo=FALSE}
ftext("")  # 这里落款前空第2行
```

```{r echo=FALSE}
ftext("")  # 这里落款前空第3行
```
 
```{r echo=FALSE}
dpmt = "大唐天子李世民"
date = as.Date(Sys.Date())
year  = as.integer(format(date, '%Y'))
month = as.integer(format(date, '%m'))
day = as.integer(format(date, '%d'))
trdate = paste0(year, "年", month, "月",  day, "日")

# 计算落款日期前的空格数
date_w = nchar(trdate, type = "width") + 2    # 实际长度要多占用两个字符
date_sp = 54 - 12 - date_w

# 计算落款单位前的空格数
dpmt_w = nchar(dpmt, type = "width")
dpmt_sp = round(54 - 12 - date_w + (date_w - dpmt_w) / 2 + 0.01, 0)
```

`r ftext(strrep(" ", dpmt_sp))`
`r ftext(dpmt)`

`r ftext(strrep(" ", date_sp))`
`r ftext(trdate)`

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

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

library(rmarkdown)
library(purrr)
library(officer)

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

params = list(
  name = data$name,
  ID = data$ID,
  address = data$address
)

gendocx = function(name, ID, address) {
  render(
    input = "report.Rmd", 
    output_file = paste0(name, "复工证明.docx")
  )
}
 
pwalk(params, gendocx)

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

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