【package officer】利用R撰写word,自动化文档输出 —— 抛砖引玉
近日,因为朋友A工作需要,提出了一个需求:每天(或每周)都需要生成日报(周报),输出到word,但是一个个填写替换,真的很麻烦,有没有快捷的方法?
例如下面的每日新闻:
或者下面的每日市场概况:
我想是不是考虑用R来完成这项工作?幸运的是,给我找到了officer这个包,专门处理word或者PowerPoint。
我对需求的理解:
- 如果只是搜集文字资料然后输出,本没什么难,用剪切板工具(例如Copied) + markdown就可以胜任,但是对于大部分商业公司来说,Word才是通用的文件格式,对于一份公司文档来说,可能不仅仅是对内交流的材料,也可能会作为外部文档交付给客户。其中的页眉页脚、标题文字格式、间距大小、公司Logo、目录等等style elements都有要求,在这一点上markdown就无法胜任了,需要兼顾文字搜集 + 排版两方面的需求。
- 因此,将文字搜集 + 排版进行分离。
- 文字搜集:采用Excel表格的方式进行;以一定的规则,设定好标题等级模板,剩下来User所需要做的,就是在特定的表格内粘贴所需的文字即可。
- 排版:交给R + package(officer)。事先设定好公司所需要的模板,资料搜集完成之后,运行程序,得到docx。
Package Officer介绍
officer包能够让R user操作Word以及PowerPoint文件,可以添加图片、表格、文字到上述的文件中,而原始文档的属性以及风格都会保留。和ReporteRs相比,Officer速度更快,并且不需要rJava。作者提到:
Make corporate reporting with minimum hassle
目标就是让企业报告的制作变得更加简单
Github 地址:https://github.com/davidgohel/officer
Online documentation:https://davidgohel.github.io/officer/
其中主要包括了六大类型主要操作:
- 添加元素
- 光标(Cursor)操作
- 移除操作
- 替换操作
- 节
- 表格与图的注解
下面我将以任务需求为导向,简述工作流程,对用到的操作语句给予解释。而其他的操作,感兴趣的读者可以查看文档。
工作流程
准备工作
主要分为两个方面:Word 与 Excel
Word
主要是对于公司文档的样式进行检查,如果不符合标准,则进行调整。有意识统一文档格式的公司,应该员工都会有标准的word模板(dtom文件),但是我看到过太多文档格式不统一的文件了,累觉不爱,每个人都有每个人的freestyle。
题外话:如果有心的读者,往后需要和word大量打交道,可以好好系统学习一下Word的排版逻辑,事半功倍。当初我也是小白,后来因为要帮导师撰写以及排版一本10万字左右的书籍,所以就花时间学习了下,真的太值了。除了对代码的支持不够好,还真没发现什么致命的缺点,排版王者不是盖的。(一不小心,成了word吹了,匿了匿了)
调整也不难:
- 确认自己文档的标题等级:
- 保证将每一个标题都涵盖进来,做到文档的标题和样式中的标题都有对应. 不管是多少级,哪怕6级7级,都要严格有对应。之所以需要做对应,是因为有很多朋友写word习惯很差,可能很多标题层级下来,写着写着想来一个小标题,这个小标题没有用样式中的标题样式,而是直接加粗一下,就算是一个小标题了, 现在是这样没问题,后期编辑和大纲查看的时候,就有的受了。
- 根据自身需求对每一级标题做格式的调整,这个是个性化的需求
- 确认自己文档中的正文:除了标题以外的内容,都是正文。正文和结构无关,只有标题和结构有关。一般而言,正文只有一种样式。但是也有的文档采用了多种正文样式。例如普通文字是一种,引文是一种,重点是一种。不管有几种,也都要保证正文在样式中也有对应。
PS:样式大家不陌生,就是这个
Excel
按照文档格式当中的标题等级,填充Excel。
前三列为标题,分别为一、二、三级标题,没有就空着,只需要填写一次即可(第一次出现),第四列为正文,每一格正文都代表一个段落。
可以看做是树状的结构,例如,第三行、第四行的正文都属于行业新闻 - 昨日头条下的正文;第五行正文则属于行业新闻 - 大公司下的正文。
朋友A的需求就是前三列的标题都是固定的,然后去填充正文内容。所以,只需要事先将前三列标题填好且保存,然后每日在excel中的context录入就可以了。可以将每一个标题下多插入一些空行,没问题,后面的程序遇到空值会自动跳过,如此,就不必因为某一标题下的内容过多,而需要额外再在excel中插入空行,节省操作。
The Program
1 | # All the packages I used |
officer中采用read_docx()
来创建一个R Object,名为rdocx。
1 | my_doc <- read_docx() # 新的rdocx对象 |
注意:style信息是非常重要的,可以说Word排版大部分精髓都在这里,这里的style包含了Word中的样式,如下图所示:
1 | # read_docx可以读取已存在的word文件 |
比较重要的是style_type
andstyle_name
,style_type
反映的是样式的类型,paragraph
就是word中的样式了,也是我们会用到最多的。style_name
在后面会用到,添加文字时设定样式时用style_name
来指定。举例而言:正文就是Normal,一级标题就是heading 1,主标题就是Title。
接下来是我的具体操作方式:
首先读取原始word文档,该文档包含了你所设定好的标题等级、页眉页脚、字体格式等等,只不过内容是我们不需要的,替换更新。
1 | # 读取原始文档 |
介绍下officer包的几个常见操作
1 | # 添加段落(paragraph),所有的文字都是以body_add_par函数添加 |
设定标题
1 | # 添加标题,Title |
从Excel中读取之前搜集的文字数据,csv格式:
1 | > data <- read_csv("data_test_2.csv") |
正文写入
对于具体的实现,肯定有其他方式,这里我根据我的理解以及结合数据搜集的特点,采用了矩阵 + 遍历的方式,in order to finish the task as soon as possible,期待大神优化和指点。
1 | m <- as.matrix(data) |
文档输出
1 | print(my_doc, target = 'result.docx') |
就测试数据而言,最终得到的测试文档docx如下图所示:
标题、字体、页眉页脚都与原文档一致,而正文内容也得到了相应的填充。
流程梳理
所以,最终的流程如下:
- 打开预先设置好的excel表格,将搜集或编辑的文字贴入excel。
- 运行程序
- 得到排版好的word
反思与探索
反思1
如果只是固定的标题模板,个人认为利用R和手动这两种方式差别不大,因为手动的话,只要事先把正文清空而标题保留的docx保存,下次再写的时候,复制粘贴编辑即可**(粘贴可在word中设定为只粘贴为纯文本,如此粘贴进来的文字自动就匹配文档格式了)**,也没什么麻烦的。
甚至,直接用word也没什么麻烦的。(😭 那我写这个文章干嘛?唉,介绍下officer这个包还是可以的,强行有用)直接用Word:
- 首先定义好各级标题样式、正文样式
- 关键: 设定好常用的几个样式的快捷键,例如Alt + 1,Alt + M等。可以做到不亚于Markdown的输入流畅度(但是代码是不行了,比不过)。
- 开心地去写吧。
在这一点上,我不想欺骗自己,发现折腾了一下,和快手耿哥一样:尽是搞一些没什么卵用的东西。
反思2
但是如果大纲模板不固定,这个方法可能稍许方便一些。例如,我的标题不再是什么行业新闻、市场概况,而是别的内容,如摘要、论文等等。
我实在是编不下去了,没看出有什么方便的地方。
反思3
其实一开始我以为需求是,文档文字内容固定,然后其中一些数值发生变化,比如当日股价收盘价XXX,涨幅XXX,当日黄金价格XXX。我觉得这种方式用工作流会有用一些。
比如,一个Excel中录入当日的这些数字,或者要替换的文字,然后运行程序,进行替换。这样效率比较高,因为如果手工进行,需要找到每个数值的位置,然后一次只能粘贴一个,效率就很低了。
我觉得应该是没问题的,officer中有光标定位函数、有替换函数,结合R字符处理函数,应该可以实现。
反思4
暂时没有考虑图片和表格的情况。但是officer中是可以添加图片和表格的。
excel中只能录入文字,如果遇到其他格式的内容怎么办?因为朋友A的文档里没那么多复杂的东西,所以就没考虑那么多了。
Last but not least
本文借助一个工作中的小例子,简要介绍了officer package的用法,探索了R与Word协作的可能性,妄想了一种日报周报自动化文档的工作流程。
还有很多可以探索与学习的地方,权当抛砖引玉,欢迎大家一起交流,恳请大神不吝指教。