是莽撞人就来单挑:从 R Markdown 到微软 Office 输出

谢益辉 2017-04-04

常年来我有两个非常难达到的目标:一个是邮件清零,另一个是浏览器标签页清零。这两个数字都不大,大约都在 40 左右。难以清零是因为里面有一些不是三两天就能搞定的想法,但我又觉得这些想法很有价值。拖着拖着一年两年过去了也不会有任何动作,感觉人都要爆炸了,所以即日起干脆列举一些出来,然后把邮件归档、浏览器标签页关掉,要是有哪些莽撞人有意去实现它们最好,没有也就算了,等我猴年马月有闲心的时候再来解决它们。

莽撞人是听郭德纲相声听来的。平时我喜欢用“壮士”称呼厉害的人。想起“莽撞人”是因为上次大为同志一口气解决掉 32 篇文章,我立刻觉得这是个莽撞人,比普通壮士还厉害。

好了,说第一个想法。很久以前我注意到了 ReporteRs 这个包,用来从 R 生成 Office 文档,如 Word 和 PowerPoint。我感觉从细节上来说,它比 Pandoc 更灵活一些,主要是因为 Pandoc 的 Markdown 能生成的元素有限,这是它的优点(强制简化你的写作),但有时候也是缺点,尤其是被 Office 毒害了大脑的用户们,总是想这里几个字涂红,那里画个表格,表格还要合并单元格,这些用户随便提个要求 Markdown 都很难满足。

对我个人而言,我压根儿不在乎这些多余的功能,我就喜欢在强约束条件下写作,免得我老是分心注意排版的事情,但问题是,Office 用户就像白绝一样乌泱乌泱的,所以三天两头就会被人问 Word 支持的问题,而且这些用户通常也不能接受强约束条件。最后一根稻草是一次芒果的博客赤果果挑衅我大 knitr 和 R Markdown,说你家的 Word 算啥 Word。

好嘛,且待我有空用键盘收拾你。然而我没空。只好先用嘴遁。

我的天,真的会有人用 ReporteRs 写 Word 文档咩?我的意思是,一个 Word 文档竟然是靠 R 函数一句一句写出来的。这特特么是不是也太反人类了。要写一个文档,操起键盘就开始写标题、作者、日期、正文段落、章节、图表等等就好了啊,肿么是从 doc = addTitle() 开始呢。

我的想法是,既然 ReporteRs 的基础设施看起来比较完备,那么我们能不能给它做一个包装:外壳用 R Markdown,底层用 ReporteRs 里的函数。这个想法有至少两种可能的实现方式:

  1. R Markdown 通过 knitr 转 Markdown,然后 Pandoc 介入,首先将 Markdown 翻译为 JSON 或其它结构化数据,然后把里面的元素一项一项传入合适的 ReporteRs 函数,生成一个大 R 脚本(脚本里包含 addTitle() 这样的 R 语句),最后通过运行这个脚本生成 Office 文档。

  2. R Markdown 到 Markdown 到 HTML,解析 HTML 文件,再动态生成 ReporteRs 语句。

后一种方式的优点是可以利用 bookdown 里一些现成的功能,比如图表编号和交叉引用,缺点是 HTML 的结构化程度可能不如 JSON,翻译 ReporteRs 语句的时候可能会困难一些。

关键的一个难点是如果别人修改了 Office 文档,如何把这些修改导回 R Markdown 里。不解决这个问题,也无法回应芒果的无情吐槽。

当然我也不是有十足的把握这两条路能行得通,里面肯定还有很多细节问题需要考虑,我对 ReporteRs 的文档也不是完全熟悉。要是信了我的话,掉进大坑浪费了时间请莫怪我。

最后吐槽一下 ReporteRs 这个包名:通常我写一篇两千字的日志完全不会觉得手酸,但今天写这篇短日志却让我的左手小指感觉好酸。我早年的时候也有这个倾向,喜欢把包名里的 R 大写,如 formatR,后来基本上只用纯小写的名字了。一个包名开头要按一次 Shift 键,然后哗啦啦敲几个字母,正中间急停,再按一次 Shift 键,然后又是小写。就问你想不想掀桌。