1. 为什么“大模型写完、Word 排版”这一步总是翻车
1.1 从一段真实的使用场景说起
大模型把内容写出来那一刻,很多人是兴奋的:结构齐整、层级分明、表格也有,看着就像一份能直接交出去的文档。但接下来发生的事情往往很扫兴——把内容复制到 Word 里,标题变成了正文,编号全乱,表格挤成一坨,代码块的缩进被吃掉,列表的项目符号有的在有的不在,字体一会儿宋体一会儿等线,行距忽大忽小。于是开始手工调:先刷标题样式,再修表格边框,再统一字体,最后发现页码和目录又得重来一遍。
这个来回折腾的过程,本质上是两种文档范式的冲突。大模型输出的是结构化纯文本(Markdown),它只描述“这是什么”——这是二级标题、这是一个无序列表、这是一段代码;而 Word 是带样式的所见即所得文档,它关心“长什么样”——用的是哪个样式集、字号多少、段前段后几个磅。中间缺少一个把“语义”翻译成“样式”的稳定环节,你靠手工复制粘贴去补这一环,就必然不稳定。
我见过太多人把这一步当成体力活,一次两次还行,一旦文档超过十页、或者需要反复迭代版本,手工排版的时间成本会指数级上升。而实际上,这一环完全可以交给工具链自动完成,关键在于你要理解它背后的映射规则。
1.2 这条链路能解决什么问题,适合谁
把Markdown 转 Word这件事做扎实,能带来的直接收益很明确:第一,内容与排版解耦,你只需要专注 Markdown 里的结构和文字,样式由模板统一兜底,改样式只改模板不动正文;第二,可重复,同一份 Markdown 每次生成的结果一致,不会出现“这次调好了下次又乱”;第三,可批量,十份、一百份文档用一条命令跑完,这在需要交付多份材料时差别巨大;第四,版本可控,Markdown 是纯文本,能进版本管理,diff 一目了然,Word 二进制文件做不到这一点。
适合看这篇内容的人,大致有三类。一类是经常用大模型产出长文档的人,比如写方案、写报告、写课程讲义,内容是模型给的,交付格式要求是 Word;一类是技术写作者和文档维护者,本来就在用 Markdown 写东西,需要导出成 Word 给非技术同事看;还有一类是需要批量出文档的岗位,比如整理会议纪要、生成标准化表单,手工做一遍可以,做一百遍就必须上工具。
需要提前说明的是,这篇内容里涉及的参数、模板配置、目录生成这些细节,有一部分是我基于长期实践总结的常见可靠做法,不同版本的 pandoc 行为会有细微差异,你在自己机器上跑的时候以实际输出为准。另外我会尽量把每个选择的理由讲清楚,因为这条链路上“为什么这么配”比“配了什么”更重要——你理解了映射逻辑,遇到新样式需求才能自己改。
1.3 先明确整条链路的边界
在动手之前,得先知道这套方案能做什么、不能做什么。能做的:标题层级、段落、粗斜体、有序无序列表、嵌套列表、表格、代码块、引用块、图片、超链接、脚注、分页符、自动目录、页眉页脚(通过模板)、编号样式(通过模板)。这些覆盖了绝大多数商务和技术文档的需求。
不太擅长的:复杂的分栏排版、图文环绕的精确定位、Word 里那种手工绘制的复杂图表、需要精细控制到某个字符位置的版式设计。这类需求本质上是桌面排版的范畴,硬用 Markdown 去逼近会很痛苦,不如在 Word 里做最后的手工微调——但要接受“微调部分不可重复”这个事实,把它控制在很小的范围内。
还有一点要提醒:不要把 Markdown 当成 Word 的替代品。Markdown 的优势是结构清晰、专注内容、便于协作和版本管理;Word 的优势是精细排版和通用交付。这条链路的价值在于把两者的优势接起来,而不是让其中一个去干另一个的活。想清楚这个定位,后面很多取舍就顺了。
2. 方案选型:为什么是 pandoc,而不是别的路
2.1 几条常见路线的横向对比
把 Markdown 变成 Word,市面上可行的路不止一条。我先把自己试过或评估过的几条路线摆出来,说清楚各自的适用面和坑。
| 路线 | 原理 | 优点 | 明显短板 | 适合场景 |
|---|---|---|---|---|
| 手工复制粘贴 | 人眼识别结构,手动套样式 | 零学习成本,单篇应急最快 | 完全不可重复,长文档必乱,表格和代码块几乎必坏 | 一页以内的临时内容 |
| 在线转换工具 | 上传文件,服务端转换 | 不用装环境,手机也能用 | 内容要上传,样式控制弱,批量困难,隐私敏感内容不适合 | 非敏感、单次、样式要求低 |
| 办公套件自带导出 | 部分编辑器支持导出 docx | 界面友好,上手快 | 样式映射固定且不可控,模板能力弱,复杂表格易错 | 轻量文档、对样式无要求 |
| 脚本 + 文档库 | 用编程方式生成文档 | 控制力最强,可编程 | 要写代码,Markdown 解析得自己做或引库,维护成本高 | 高度定制、结构化数据生成 |
| pandoc + 参考模板 | 命令行转换,样式来自 docx 模板 | 映射规则清晰、模板可控、可批量、可进流水线 | 需要理解样式名映射,初次配置有门槛 | 长文档、批量、需统一风格 |
从表里能看出来,pandoc 这条路线赢在中间位置:比手工和在线工具可控得多,比纯编程生成省事得多。它的核心机制其实很朴素——pandoc 内部先把 Markdown 解析成一棵抽象语法树,再按目标格式的规则输出;输出 docx 时,它会给每个语义元素套上一个具名样式(比如一级标题套Heading 1,代码块套Source Code),样式具体长什么样,则由你提供的参考文档决定。
这个设计是整个方案的基石。它意味着你不需要会写 Word 的任何二进制细节,只需要在 Word 里把样式调好一次,存成模板,之后所有转换都继承这套样式。内容与样式的解耦,就发生在这一层。
2.2 pandoc 的核心机制:样式名是唯一的握手协议
很多人第一次用 pandoc 转 Word,会发现输出“能看但不好看”,标题是蓝色的、字体是默认的、代码块背景是灰的。于是以为 pandoc 排版能力弱。其实不是,是你没给它模板。不给模板时,pandoc 用内置的默认参考文档,那份文档的样式非常朴素。
理解了“样式名是握手协议”这件事,很多困惑就解开了。pandoc 输出 docx 时,认的是样式名称,不是样式的外观。你模板里有个样式叫Heading 1,它就把所有一级标题往里塞;你把Heading 1改成黑体二号加粗居中,输出就跟着变;你要是把样式改名成一级标题,pandoc 就找不到了,只能退回默认样式。
所以整条链路的关键动作是:用一条命令导出一份参考模板,在 Word 里把里面每个样式改成你要的样子,样式名一个字都不要动,再用这份模板去做转换。这个动作做一次,后面所有文档都受益。
注意:样式名区分得很死,包括空格。
Heading 1和Heading1是两个不同的名字。在 Word 的样式窗格里改样式时,只改格式属性,不要顺手重命名。
2.3 版本与依赖:几个容易忽略的前置条件
pandoc 是单文件可执行程序,安装本身不复杂,但有几个前置条件容易绊人。第一,版本要够新。docx 输出相关的修复大多集中在较新的版本里,尤其是表格宽度、嵌套列表、代码块换行这几块,老版本的表现会让你怀疑人生。我一般建议用近一两年内的稳定版,装完先跑pandoc --version确认。
第二,中文字体依赖。如果你的模板里指定了中文字体,转换机器上必须装了这个字体,否则 Word 打开时会回退到别的字体,看起来“模板没生效”。这在跨机器协作时特别常见:你本地调好的模板,同事那边打开就变样,十有八九是字体缺失。
第三,如果文档里有图片或需要生成目录,得确认模板里对应位置有正确的域代码(目录)和图片样式。图片这块还有个隐藏坑:pandoc 默认会按图片原始尺寸插入,大图会撑破页面,需要用参数限制最大宽度。
第四,编码问题。Markdown 文件请统一用 UTF-8 保存,带 BOM 的文件在某些工具链里会出现首行异常或多出不可见字符,排查起来很费时间。
3. 从零搭一套可复用的转换环境
3.1 环境准备与最小验证
装好 pandoc 之后,别急着上手正式文档,先用一个最小的样例把链路跑通,确认每一步的输入输出都符合预期。这个习惯能帮你把“工具问题”和“内容问题”分开。
准备一个测试文件,内容覆盖你实际文档里会用到的所有元素:多级标题、段落、粗斜体、有序无序列表、嵌套列表、表格、代码块、引用、图片、超链接。文件不用长,但元素要全。然后执行一条最朴素的转换命令:
pandoc test.md -o test.docx打开生成的 docx,逐项检查:标题层级对不对、表格有没有丢列、代码块缩进在不在、列表嵌套有没有塌掉。这一步的意义在于建立一个基线认知——知道“裸转换”长什么样,后面加了模板才能对比出改进在哪。
如果你想导出一份参考模板来改,命令是这样的:
pandoc --print-default-data-file reference.docx > reference.docx这条命令会把内置的参考文档释放到当前目录。用 Word 打开它,你会看到里面有一堆占位段落,每一段都用了一个特定样式,旁边通常标着样式名。这些占位内容就是给你看样式的,改完样式之后把这些占位段落删掉或保留都行——pandoc 只读样式定义,不读正文内容,但为了清爽起见我一般会清掉。
3.2 参考模板的制作流程与样式映射表
模板制作是整件事里最值得投入时间的一步。我的做法是:先规划文档需要哪些样式,再逐个在模板里落地。下面这张表是我常用的样式映射,左边是 Markdown 里的语义,右边是 docx 里对应的样式名(这些名字是 pandoc 认的,不要改)。
| Markdown 元素 | 对应 docx 样式名 | 常见调整点 |
|---|---|---|
#一级标题 | Heading 1 | 字号、段前段后、是否居中、是否另起页 |
##二级标题 | Heading 2 | 字号递减、与正文的间距 |
###三级标题 | Heading 3 | 加粗与否、颜色 |
| 普通段落 | Body Text 或 First Paragraph | 行距、首行缩进、字体 |
| 无序列表 | Compact 或 List Paragraph | 项目符号样式、缩进层级 |
| 有序列表 | Compact 或 List Paragraph | 编号格式、缩进 |
| 代码块 | Source Code | 等宽字体、背景色、字号调小 |
| 行内代码 | Verbatim Char | 等宽字体、浅底色 |
| 引用块 | Block Text | 左缩进、左边框、字体颜色 |
| 表格 | Table | 边框、表头底纹、单元格边距 |
| 图片 | Figure / Caption | 居中、题注样式 |
| 超链接 | Hyperlink | 颜色、是否下划线 |
具体操作:在 Word 里打开参考模板,找到样式窗格,逐个定位到上表里的样式名,右键修改。这里有几个实操细节值得说。
正文样式的选择要留意。pandoc 在输出时,段落的第一个段和后续段落可能套不同样式(First Paragraph和Body Text),如果你只改了Body Text没改First Paragraph,会发现每节第一段的格式跟后面不一样。解决办法是把两个样式改成完全一致,或者干脆在模板里把First Paragraph的格式同步过来。
列表样式的坑最深。pandoc 对列表的处理依赖Compact和List Paragraph这类样式,而 Word 的列表编号和缩进又跟“列表级别”绑定。嵌套列表塌掉、编号从中间重新开始,基本都是这里的问题。我的经验是:在模板里把列表样式的缩进手工设好每一级,不要依赖 Word 的自动编号继承,输出会稳很多。
代码块样式要单独调。Source Code这个样式默认字号偏大、没有背景,长代码块会很难看。调成等宽字体、字号比正文小一到两磅、加浅灰底纹、设置段前段后小间距,可读性会好很多。另外代码块里的长行不会自动折行,这个在后面的问题排查里会专门讲。
3.3 一条命令跑通完整转换
模板准备好之后,转换命令其实很短,但参数值得逐一说清楚:
pandoc input.md \ --reference-doc=reference.docx \ --toc \ --toc-depth=2 \ -o output.docx--reference-doc指定样式来源;--toc生成目录,注意它生成的是一个域,在 Word 里打开后可能需要按 F9 或右键“更新域”才会显示页码,这是正常现象,不是没生成;--toc-depth=2控制目录收录到几级标题,一般到二级就够了,收太深目录会冗长。
如果文档里有图片,建议加上宽度限制,避免大图撑破版心:
pandoc input.md \ --reference-doc=reference.docx \ --toc \ -o output.docx \ -V maximum-image-width=15cm需要说明的是,图片宽度的控制方式在不同版本和不同输出格式下支持度不一样,-V传变量对 docx 输出未必生效。更稳的做法是在 Markdown 里直接写宽度属性,或者在模板里把Figure样式设成居中并给图片所在的段落设好版心限制,再配合对图片源文件做预处理(提前把超大图压到合理尺寸)。我一般两条腿走路:源图先压一遍,模板里再把图片段落设成居中,双保险。
4. 核心细节:让输出真正“能交出去”的关键处理
4.1 标题编号:交给样式还是交给正文
这是一个必须先做决定的问题:文档里的“1.2.3”这种编号,是写在 Markdown 正文里,还是让 Word 通过多级列表自动生成?
写在正文里的好处是所见即所得,转换前后编号完全一致,不依赖 Word 的域;坏处是增删章节要手工重排,容易漏改。交给 Word 自动编号的好处是增删自动更新,符合 Word 的使用习惯;坏处是配置在模板里,配错了整个文档编号全乱,而且转换出来的 docx 在不同 Word 版本里表现可能有差异。
我的实际选择是:正式交付文档用 Word 多级列表自动编号,模板里配好一次;临时或短文档直接在 Markdown 里写死编号。理由很实在——交付文档会被别人改,别人增删章节时自动编号能兜住;而短文档你自己控制,写死更省心。
配自动编号的要点:在模板里给Heading 1到Heading 3分别绑定多级列表的对应级别,级别与样式挂钩,编号格式设成“1”“1.1”“1.1.1”,并确保“重新开始编号”的设置正确。这里最容易出的问题是二级标题编号不跟随一级——原因通常是各级别没有正确链接到样式,或者“正规形式编号”没勾。这个配置一旦错,靠改正文是救不回来的,只能回模板重修。
提示:如果你在 Markdown 里已经写了
## 1. 项目概述这种带编号的标题,同时又启用了 Word 自动编号,输出会出现“1. 1. 项目概述”这种双编号。二选一,别混用。
4.2 表格:从“能显示”到“能看”
Markdown 的表格语法很朴素,用竖线分隔,第二行写对齐方式。pandoc 转成 docx 时会生成真正的 Word 表格,但默认样式往往很素:无边框或只有横线、表头没底纹、列宽按内容平均分、单元格文字紧贴边框。
要让表格“能看”,需要三处配合。第一,模板里的Table样式:设置统一边框(建议细实线)、表头行加浅底纹、单元格设置合适的上下左右边距(比如 0.1 厘米),这些在表格样式的属性里都能配。第二,列宽控制:pandoc 会根据 Markdown 里表头分隔线的相对长度来推算列宽比例,所以你可以通过调整分隔线里短横线的数量来暗示列宽,比如|:-----|:---|表示第一列宽、第二列窄。这个技巧很实用,但要注意它只是“暗示”,实际渲染还受内容长度影响。第三,超宽表格的处理:列数多的表格在 A4 纵向版心里必然挤,解决办法要么改成横向页面(在模板里做一个横向节),要么把表格拆成两张,要么缩小表格字号。缩小字号这个做法在模板里给表格单独定义一个更小的字号样式即可,比逐表调格式省事。
还有一个隐蔽的坑:单元格里的内容如果包含竖线字符,会把表格结构撑坏。Markdown 表格里表示竖线需要用转义,否则解析器会把它当成列分隔符。同样,单元格里想换行,标准 Markdown 表格语法不支持,得用 HTML 的<br>,pandoc 会识别并转成 Word 里的换行。这两点在写内容时就要注意,别等转换完发现表格结构错乱再回头找。
4.3 代码块与行内代码的排版处理
技术类文档里代码块是重头戏,而它恰恰是最容易排坏的部分。三个高频问题:长行溢出、缩进丢失、中英文混排错位。
长行溢出是因为代码块默认不折行,一行超出页宽就会被裁掉或顶出边界。Word 里对段落可以设置“允许西文在单词中间换行”,但对代码来说更好的做法是在源头控制行宽——写代码示例时主动在 80 到 100 字符处断行,或者在转换后用脚本检查超长行。指望工具自动折行,往往会折在奇怪的位置,可读性反而更差。
缩进丢失通常发生在你从聊天窗口复制内容时,制表符和空格被混淆了。统一用空格缩进,并且确认复制过程中没有把连续空格压缩成一个。有些编辑器有“粘贴时保留格式”的选项,关掉它,用纯文本粘贴更保险。
中英文混排错位是个视觉问题:等宽字体里中文字符宽度通常是英文字符的两倍,如果字体本身对中文支持不好,代码块里的中文注释会显得忽宽忽窄。解决办法是给Source Code样式指定一个中英文都覆盖得比较好的等宽字体,并且字号统一,不要一部分大一小时。
4.4 图片、题注与交叉引用
图片这块的完整需求通常是:图片居中、有题注、题注带编号、正文里能引用“见图 3”。pandoc 的 Markdown 语法里,图片的 alt 文本会成为题注(在 docx 输出中表现为Caption样式),但自动编号和交叉引用它不负责。
所以我的做法是分两层:图片插入和题注样式交给 pandoc 和模板,题注里的编号在 Markdown 里手工写(比如“图 1 系统整体结构”),正文引用也手工写“见图 1”。这样做不完美——增删图片要手工改编号——但稳定可靠,不会因为域更新失败导致整篇文档出现“错误!未找到引用源”。
如果文档图片很多、改动频繁,值得上 Word 的题注域和交叉引用域,但那需要在转换后手工插入或写脚本处理,复杂度上一个台阶。我的建议是:图片少于十张,手工编号;超过十张且会频繁增删,再考虑上域,不要为了少数场景把链路搞复杂。
图片尺寸控制前面提过,核心原则是源图先压到合理分辨率(屏幕阅读 150 到 200 dpi 足够,打印 300 dpi),单张图宽度不超过版心宽度。版心宽度怎么算:A4 宽 21 厘米,左右页边距各 2.5 厘米的话,版心就是 16 厘米,图片宽度设成 15 厘米留点余量最稳。
5. 完整实操流程与参数落地
5.1 从原始内容到成品文档的六步流程
把前面所有细节串成一条可执行的流水线,我平时是这么走的,六步,每步都有明确的产出物。
第一步,内容整理。把大模型输出的内容落到一个.md文件里,检查三件事:标题层级是否连续(不要从一级直接跳三级)、列表嵌套是否用了统一缩进(建议两空格或四空格,全文一致)、表格的竖线数量每行是否一致。这一步花五分钟,能省后面半小时的排错。
第二步,元素补全。补上 code fence 的语言标识(即使是纯文本也标上,方便后续高亮)、给图片加上有意义的 alt 文本(它会变成题注)、把需要分页的地方插入分页标记。pandoc 支持用\newpage或特定的 raw block 分页,具体写法随版本略有差异,我一般用一个独立的空段落加自定义样式来做分页控制,更稳。
第三步,模板确认。确认reference.docx是最新版,样式名没被改过,中文字体在当前机器上存在。这一步看起来琐碎,但它是“输出不一致”问题的最大来源。
第四步,执行转换。用带完整参数的命令跑一遍,把输出重定向到指定目录,命令和日志都保留,方便回溯。
第五步,成品校验。打开 docx,按清单逐项过:目录是否生成(记得更新域)、标题编号是否连续、表格边框和列宽是否合理、代码块有没有溢出、图片是否居中且不超宽、页眉页脚是否正确、页码是否从正文开始。这个清单建议固化成一张表,每次照打勾。
第六步,微调与归档。把必须在 Word 里手工处理的部分(如果有)集中处理,然后在文件属性里写上版本和日期,连同源 md 和模板一起归档。归档时一定要保留源文件,因为下次内容更新时,你要从 md 重新生成,而不是在 docx 上改——在 docx 上改意味着这条链路断了。
5.2 参数计算:页边距、字号与行距的配合
排版好看不好看,很大程度上取决于几个数值的配合,而这些数值是可以算出来的,不用凭感觉试。
版心宽度:A4 纸宽 21 厘米,减去左右页边距。学术和商务文档常用 2.5 到 3 厘米边距,取 2.5 厘米的话版心是 16 厘米;取 3 厘米则是 15 厘米。版心宽度决定了正文一行的字数和图片最大宽度。
每行字数:中文正文常用小四(12 磅)或五号(10.5 磅)。以 12 磅字、版心 16 厘米计算,一个汉字约占 12 磅即约 0.42 厘米,一行约 38 字。这个数量偏多,阅读时眼睛回扫距离长,容易累。想控制在 32 到 35 字,可以把字号提到小四偏大或把版心收窄到 14 厘米左右。行宽 32 到 38 字是中文长文档比较舒服的区间,超出就该调。
行距:正文行距设 1.5 倍或固定值 22 到 24 磅比较耐读。固定值的好处是行距绝对均匀,不受字体度量影响;倍数行距的好处是随字号自适应。我一般用固定值,因为中英文混排时倍数行距容易出现行间疏密不均。
段间距:段前 0、段后 6 到 8 磅,配合首行缩进 2 字符,是中文文档的常规做法。标题的段前段后要给足,一级标题段前 18 到 24 磅、段后 12 磅左右,视觉上才有清晰的章节分隔感。
这些数值不是死的,但它们之间有依赖关系:改字号就要重算每行字数,改版心就要重算图片最大宽度。理解这层依赖,你调模板时就不会东改一下西改一下,改完发现整体不协调。
5.3 目录、页眉页脚与分节的实际配置
目录的问题前面提过,这里说透一点。--toc生成的目录是一个 Word 域,pandoc 写入的是域的初始结果(通常是空的或占位的)。你在 Word 里打开,需要右键目录区域选择“更新域”,再选“更新整个目录”,页码和条目才会出现。如果更新后是空的,说明模板里的标题样式没有被目录识别——检查标题样式是否基于 Word 内置的 Heading 样式,自定义样式名是不会被目录收录的。
页眉页脚必须在模板里配。做法是打开参考模板,进入页眉编辑状态,写上你要的内容(可以是静态文字,也可以是域,比如页码域)。pandoc 转换时会保留模板的页眉页脚设置,但不保证每个节都继承,所以如果你的文档有分节(比如封面不显示页码、正文从 1 开始),需要在模板里就把分节结构做好。
封面和正文分离是常见需求:封面不要页眉页脚、不要页码,正文从第一页重新编号。实现方式是在模板里做一个两节的文档结构,第一节是封面(设置“首页不同”或独立节且不链接到前一节),第二节开始正文并把页码起始值设为 1。这个配置一次做好,之后所有文档都受益。这里的关键认知是:模板不只管样式,还管页面结构。很多人只把模板当成“字体字号配置”,忽略了节、页眉页脚、页码这些结构性设置,结果每次都要手工补。
5.4 批量转换的脚本化写法
单篇转换用命令行就够了,多篇的时候值得写个小脚本。核心思路是遍历目录下的 md 文件,逐个调用 pandoc,把输出放到指定目录,记录每篇的成功或失败。
#!/usr/bin/env bash set -euo pipefail SRC_DIR="./md" OUT_DIR="./docx" TPL="./reference.docx" mkdir -p "$OUT_DIR" for f in "$SRC_DIR"/*.md; do base=$(basename "$f" .md) echo "converting: $base" pandoc "$f" \ --reference-doc="$TPL" \ --toc \ --toc-depth=2 \ -o "$OUT_DIR/$base.docx" done这段脚本有几个细节值得说。set -euo pipefail让脚本在任一命令失败时立即停止,避免半途出错还继续跑;basename取文件名去掉扩展名,保证输出名和源文件对应;mkdir -p保证输出目录存在。如果某篇转换失败,脚本会停下并报错,你能立刻定位是哪一篇。
批量场景还有一个常见需求:每篇文档的标题不同,但都要写进页眉或封面。这时可以用 pandoc 的元数据(YAML front matter)传递变量,在模板里用域引用,或者在转换后用脚本改 docx 的页眉文字。前一种方式更优雅但配置复杂,后一种更直接。我的经验是,如果只是改个标题文字,转换后用脚本处理 docx 的 XML 反而更省事,但要注意 docx 本质是 zip 包,改完得正确重新打包,别破坏了结构。
6. 常见问题与排查实录
6.1 高频问题速查表
下面这张表是我在实际使用中反复遇到、也被问过最多的问题,按现象、原因、解法三列整理,建议收藏备用。
| 现象 | 大概率原因 | 解法 |
|---|---|---|
| 模板样式完全没生效 | 没传--reference-doc,或路径错,或样式名被改过 | 确认参数和路径;打开模板核对样式名是否与 pandoc 约定一致 |
| 标题是蓝色的默认样式 | 用了内置默认参考文档,未提供自定义模板 | 导出reference.docx并改Heading 1到Heading 3 |
| 每节第一段格式和其他段不同 | 只改了Body Text没改First Paragraph | 两个样式改成一致,或同步格式 |
| 嵌套列表塌成一层 | 列表样式缩进未分级,或源文件缩进不统一 | 模板里逐级设缩进;源文件统一用两或四空格 |
| 编号出现双份(1. 1.) | Markdown 里写了编号,Word 又开了自动编号 | 二选一,去掉其中一处 |
| 表格没有边框或边框不全 | 模板的Table样式没设置边框 | 在表格样式属性里统一设细实线边框 |
| 表格列宽挤在一起 | 内容长且未暗示列宽比例 | 调整分隔线短横线数量;或缩小表格字号 |
| 代码块长行被裁掉 | 代码块不自动折行,行宽超版心 | 源头控制行宽在 80 到 100 字符;或调小代码字号 |
| 代码块缩进错乱 | 制表符和空格混用,或复制时空格被压缩 | 全文统一空格缩进,用纯文本方式粘贴 |
| 图片撑破页面 | 图片原始尺寸超过版心宽度 | 源图预压缩;模板设图片段落居中并限宽 |
| 目录是空的 | 域未更新,或标题样式非内置 Heading | 在 Word 里更新域;核对标题样式是否基于内置样式 |
| 打开后字体全变了 | 转换机器上缺模板指定的中文字体 | 在目标机器安装对应字体,或换用通用字体 |
| 中文出现方框或乱码 | 编码不是 UTF-8,或字体不支持中文 | 统一 UTF-8 保存;指定支持中文的字体 |
| 超链接样式丢失或变黑 | 模板未定义Hyperlink样式 | 在模板里补上超链接样式并设颜色 |
6.2 三个我踩过最深的坑
第一个坑:以为模板改了就一定生效,结果改错了地方。早期我在 Word 里改样式,习惯直接选中正文文字改字体字号,这改的是“直接格式”,不是样式定义。pandoc 读取的是样式定义,直接格式它看不见。所以正确做法是在样式窗格里右键样式名,选“修改”,在弹出的对话框里改,而不是选中文字改。这个区别看起来小,但它决定了你的所有修改是否被工具链继承。我在这上面浪费过好几个小时,反复怀疑是 pandoc 的问题。
第二个坑:列表样式跨版本不一致。同一份 md、同一个模板,在不同机器上转出来的列表缩进不一样。排查发现是 Word 版本差异导致列表样式的“列表级别”继承行为不同。解决办法是在模板里把每个列表级别的缩进用绝对值写死(比如一级缩进 0.74 厘米、二级 1.48 厘米),不依赖“相对于上一级”的相对设置。改完之后跨机器就一致了。这个经验说明一件事:模板设计要尽量用绝对值,少用相对继承,稳定性会好很多。
第三个坑:内容里混入了不可见字符。有一次转换出来的文档,某几个段落前面总是多出奇怪的空格,怎么改样式都没用。最后把 md 文件用十六进制方式打开才发现,里面混了不换行空格(NBSP)和零宽字符,是从某个网页复制内容时带进来的。这类问题的排查思路是:怀疑内容而不是怀疑工具。可以用简单的命令检查文件里的非 ASCII 非常规字符,或者用编辑器的“显示不可见字符”功能过一遍。养成从聊天窗口往编辑器粘贴时先过一道纯文本的习惯,能避免大半这类问题。
6.3 让输出更稳的几条独家习惯
第一条,模板和内容分目录管理,模板单独版本化。我一般建一个templates目录放reference.docx,文件名带版本号比如reference-v3.docx,每次改模板升一版,并且在一个小文本里记一句改了什么。这样做的好处是出问题能回滚,而且能对比两版模板的差异定位问题。
第二条,先跑最小样例再跑正式文档。每次升级 pandoc 或改模板后,先拿那个包含全元素的测试文件跑一遍,确认没有回归,再处理正式内容。这个习惯帮我拦下过好几次升级导致的表格样式变化。
第三条,转换命令写进脚本或 Makefile,不靠记忆。参数一多,靠手打必然出错,而且不同人打出来的参数可能不一样,输出就不一致。把命令固化下来,谁跑都是同一套参数。
第四条,成品校验清单化。前面提过的那张清单,我建议真的做成一张表,每次交付前逐项打勾。目录、编号、表格、代码块、图片、页眉页脚、页码,七项,两分钟能过完,能拦住绝大多数交付事故。
第五条,保留源文件和中间产物。源 md、模板、转换命令、生成的 docx,四样一起归档。将来内容要更新时,从 md 改,重新生成,而不是在 docx 上打补丁。这条是整条链路可持续的根本——一旦你开始在 docx 上手工改内容,这套自动化就名存实亡了。
6.4 什么情况下该果断放弃自动化
最后说个反向的经验。这套链路不是万能的,有些场景硬上自动化反而更累。页数很少、样式要求极简的文档(比如一页的会议纪要),手工排比配环境快;版式高度定制、有大量图文混排和艺术化设计的文档(比如宣传册、海报式文档),这属于桌面排版范畴,Markdown 表达不了那么细的控制,强行逼近会做出一堆妥协;需要多人协同在 Word 里直接编辑并留痕的文档,如果协作方只用 Word,那源头就该是 Word,用 Markdown 生成再转过去,协作环节会割裂。
判断标准其实很简单:这份文档的内容会不会反复更新、要不要批量生产、需不需要版本可追溯。三个里有两个是肯定的,就值得上这套链路;三个都是否定的,手工做完就完了,别为了工具而工具。我自己是这么划线的,省下来的时间比搭环境投入的多得多。