乐于分享
好东西不私藏

word排版工具 com接口太慢,换成了xml+com结合

word排版工具 com接口太慢,换成了xml+com结合

主要内容:
  1. 对wps做了一些bug修复,速度上有效提升,解决了异常弹窗,用户可直接覆盖安装。
  2. 专门对word做了一个优化版本,必须要在word上用的话,现在只是略逊于wps
  3. 关注公众号回复[排版工具]可获取软件链接
正文
事情是这样的。
前阵子有个朋友找我,说他们公司IT政策很严,不让装WPS,也不让装任何第三方软件,电脑里只有微软Office。但他平时干活又需要处理大量Word文档,提取标题、整理结构这些事情,手动做到手抽筋。
我们之前做的Inkwell工具,WPS版跑得挺好的,但Word版因为依赖COM接口,遇到大文档就拉胯。他试了一下,五百页的标书,点个扫描,进度条爬得比蜗牛还慢,直接劝退。
“能不能想想办法?”他问。
得,那就专门给Word用户做个优化版吧。

原罪是COM

COM这东西,说白了就是Word这个程序和你写的脚本之间的“传话筒”。你每问一句“这段落是什么级别”,它就要跑到Word那边问一声,再跑回来告诉你。
一趟几十毫秒,五百页跑下来几千趟,几分钟就这么没了。
关键是,很多公司环境就是只有Word,没得选。所以这个问题必须解决,拖不得。

想过很多办法,都不太行

一开始想走捷径,找现成的库。
python-docx?能读段落,但拿不到大纲级别。只能靠样式名去猜,比如看到“Heading 1”就认为是标题。但用户的文档五花八门,很多人根本不按样式来,猜错一个目录就全歪了。
直接解压docx读XML?.docx本质上是个zip包,解出来里面的document.xml就是文档正文。这招速度确实快,但我们被表格坑惨了——表格里的段落,在XML里的顺序和COM接口的Paragraphs.Item(i)对不上,算出来的索引跳转老是偏移,定位不准。
折腾了好几个晚上,一度想放弃了。

最后的方案:XML负责快,COM负责准

后来转念一想,为什么非要二选一呢?各取所长不就行了。
第一步,XML全量扫描,把标题都捞出来。
直接解压docx,用lxml解析document.xml,遍历所有段落标签,大纲级别从w:outlineLvl属性里读。这一步全程不碰COM,速度快到飞起——五百页文档,一两秒跑完。
顺便用XML里的fldChar域标记把目录页自动跳过,比原来用COM算Range.Start省事多了。
第二步,只对标题用COM做精准注入。
标题捞出来了,但要在Word里给它们加书签、做跳转,这活只有COM能干。不过这时候COM的工作量已经小很多了——XML扫描的时候顺手把每个段落对应的COM索引算好,然后直接用Paragraphs.Item(index)精准定位。
原来要调用几千次COM,现在只调用几十次(标题的数量),开销降了两个数量级。
跟WPS版比,实话实说还是没跑赢。这里补充说明一下,WPS走的其实也是COM,不是有什么神秘的“原生API”。但WPS对COM的实现做了不少优化,接口响应就是比Office的COM快一截,这点得认。同一个文档,WPS版跑起来就是更轻快。
不过Word版至少从“完全没法用”变成了“基本够用”,不至于太丢人。
朋友反馈说现在能用起来了,我心里这块石头也算落地了。

说句实在话

虽然专门给Word做了一版优化,但如果你问我个人推荐哪个——我还是推荐WPS。
可能是我用习惯了,WPS在COM接口层面的优化确实比Office做得好,同样的调用逻辑跑起来就是顺畅。而且WPS对国内用户的一些使用场景(比如公文模板、排版习惯)照顾得更细致,这些是Office比不了的。当然,这纯粹是个人偏好。工具这东西,用着顺手就是最好的。关键是看你的环境允许用什么。
如果你的公司没有软件限制,我建议你先试试WPS版,体验确实更流畅。如果公司规定只能用Office,那这个Word优化版至少能让你不用对着进度条干瞪眼。
两个版本我都放出来了,按需取用就行。

给同样折腾自动化的朋友

这次踩坑最大的收获就是:
别迷信单一方案,也别死磕一个技术。
COM慢,但有些事只有它能干。XML快,但有些细节它搞不定。把两者结合起来,COM用在“不得不用的地方”,其他地方用XML替代,复杂度就从O(总段落数)降到了O(标题数)。
如果你的场景也是公司限制只能用Word,并且需要处理大文档的结构提取,这个思路供你参考。
工具本身我放到网上了,搜“Inkwell 琢墨”应该能找到,Word版和WPS版分开发布,按需取用。
希望能帮到有同样困扰的朋友。
文档排版最崩溃的 5 件事,一个工具全解决
为了这两个小功能,我硬刚了Word五天