0%

合并RTF文件

本来想先一篇SAS-从入门到放弃文章,但是想想我才看了2-3天的SAS,怕被打脸。。。但是说真的:

  • SAS真不能算一门编程语言(语法相对比较简单)
  • 应用范围真不广,除了银行/药企还在招SAS程序员,其他应该比较少见了吧,网上资料也比较少
  • 对于数据分析来说有过于繁琐(写一个小功能得写好多代码,这点真不能忍。。因为我觉得数据分析在保证准确率的前提下,更加需要考虑的是效率的问题,因为数据是有时效性的。。),更加不用说建模/探索性分析(EDA)/机器学习(ML)等等;虽然SAS有专门针对这些分析的模块,但是收费(你懂的。。。)

正如我前一篇博文(Using huxtables in rmarkdown to export RTF)中所提到的,一般在临床数据报告中会采用RTF格式,当然RTF在其中有着其独到及方便之处,所以在该领域应用较为广泛;而且对应一些情况,SAS出RTF报告有个习惯:每次只出一页报告,最后将多个1页报告合并起来生成最终一个RTF报告,这样做的原因各种各样,在此就不提了

RTF From SAS

那么当你遇到想要合并RTF这个需求时,该如何解决呢?

首先你可以在网上搜寻下是否有相关的网页工具,毕竟有现成的工具会节省不少事件,如:https://products.groupdocs.app/merger/rtf

但是如果理解RTF或者了解RTF相关代码的话,那么通过编程写一个工具也是可以的;比如参照这篇文章(SAS-如何简单快捷的实现RTF合并)里的方法:

  • 除首个RTF文件外,删除其他RTF文件第一行中的"{"(在第一个)
  • 除最后一个RTF文件外,删除其他RTF文件最后一行中的"}"(在最后一个)
  • 在每两个RTF文件的代码间插入一行RTF代码

上述中前俩个比较好理解,为了就是将RTF拼起来;第三个的作用其实是为了分页,那么如何找到你生成的RTF分页的代码是什么呢?你可直接抄那篇文章中所提到的代码,但如果我们仔细思考下,其实可以在你用SAS已生成的RTF文件中找到,比如我打开一个RTF文件,如下所示:

rtf

将上图中的rtf代码略做修改后,\sect\sectd\linex0\endnhere\pgwsxn16837\pghsxn11905\lndscpsxn\headery1440\footery1440\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440,可看出其多了\sect;剩下的代码是其大致定义了格式参数(包括:长宽以及横向等等,我也没太了解,是猜的。。。)

明白原理后就可以用任何语言的脚本来拼接合并RTF文件了,比如用R脚本的话,简单写个示例(读入两个rtf文件,然后拼接):

# First file
file1 <- readr::read_lines("../Desktop/dm.rtf")
file1[length(file1)] <- stringr::str_sub(file1[length(file1)], end = -2)
# Second file
file2 <- readr::read_lines("../Desktop/lb.rtf")
file2[1] <- stringr::str_sub(file2[1], start = 2)
# Break page
line <- "\\sect\\sectd\\linex0\\endnhere\\pgwsxn16837\\pghsxn11905\\lndscpsxn\\headery1440\\footery1440\\marglsxn1440\\margrsxn1440\\margtsxn1440\\margbsxn1440"
# Merge files
file <- stringr::str_c(c(file1, line, file2), sep = "\\n")
# Write to file
readr::write_lines(file, "../Desktop/r_merged.rtf")

RTF From Rmarkdown

假如RTF是由Rmarkdown生成的话,就没有将每个RTF拼接的需求了,所有表格会生成在一张RTF中(我是这么认为的。。)

那么我会遇到一个问题:

如何在Rmarkdown生成RTF过程中插入分页符(break page),对于pdf/word报告,这个文件比较好解决,但是对于RTF报告,这个解决方案在网上少有人提到(可能这个方面的需求比较少吧。。。)

后来我在rtf包中找到有个添加分页符的函数,我将其源码取出来,放到rmarkdown中,然后使用knitr包的raw_output函数来转化rtf的函数输出

rtf包提取出的函数如下:

add.paper.size<-function(width=8.5,height=11) {
  paste("\\paperw",round(width*1440,0),"\\paperh",round(height*1440,0),"\\widowctrl\\ftnbj\\fet0\\sectd",if(width>height){"\\lndscpsxn"} else {""},"\\linex0",sep="")
}

add.page.margins<-function(margins=c(1,1,1,1)) {
  paste("\\margl",round(margins[2]*1440,0),"\\margr",round(margins[4]*1440,0),"\\margt",margins[3]*1440,"\\margb",margins[1]*1440,sep="")
}

add.page.break<-function(width=8.5,height=11,omi=c(1,1,1,1)) {
  paste("\\pard{\\f1\\sect}\\sectd", add.paper.size(width=width,height=height), add.page.margins(omi),"\\left\\widctlpar\\fi0\\f2\\fs18",sep="")
}

然后在rmarkdown中加入下述代码即可分页了:

echo
1
knitr::raw_output(add.page.break())

以上是我个人的小小解决办法,若大家有更好的方法请可告知我下哈,多谢啦~

参考资料

https://cloud.tencent.com/developer/article/1523493
https://cloud.tencent.com/developer/article/1636758
https://cran.r-project.org/web/packages/rtf/rtf.pdf
https://github.com/schaffman5/rtf/blob/master/R/rtf.R

本文出自于http://www.bioinfo-scrounger.com转载请注明出处