Markdown / Word

当合作者说「直接发个 Word 给我」,LaTeX 用户的一天就结束了。搭桥的常规做法是 pandoc——一个在 Markdown、LaTeX 和 .docx 之间往返的转换器,但两个方向的脾气完全不同。Word → LaTeX 是在补出原本不存在的结构,所以不会丢东西。LaTeX → Word 正相反:它把你辛苦搭起来的结构压平——\label\ref 的对应、\newcommand 的含义、公式的结构。LaTeX 是一段程序,.docx 是结果的记录。你可以运行程序并保存结果,却无法从结果反推出程序。这个不对称就是本页的主线。

为什么 LaTeX → Word 丢得更多

答案很简单:目的地没有可以接住它的东西。 .docx 本质上是一只装段落、字符格式和样式名的容器,它既没有相当于 \newcommand 的机制,也没有重新计算 \ref 所指编号的机制。于是 pandoc 把你的意图翻译到 Word 词汇够得着的地方,够不着的就丢掉。编号被冻结成当时算出的那个数,交叉引用变成普通文字而非活链接。反方向轻松得多。Word 文档除了标题层级、列表和粗体之外几乎没有结构,pandoc 只需把它们映射成 \sectionitemize信息只会增加,不会减少。这种不对称也刻在 pandoc 自己的历史里:.docx输出到 2012 年的 pandoc 1.9 才有,而读取(并且能理解修订记录)是 Jesse Rosenthal 在 2014 年加入的——距项目开始已经过去六年和八年。

pandoc 的基本用法:-f-t--pdf-engine

pandoc 的用法就是用 -f--from)指定输入格式、用 -t--to)指定输出格式。中间放着一棵抽象语法树(AST):输入侧的 reader 造出 AST,输出侧的 writer 写出结果——正因如此,格式组合变多时实现量不会呈乘法增长。作者 John MacFarlane 是加州大学伯克利分校的哲学教授,当初写它是为了学 Haskell。2006 年 8 月 3 日发布的第一版约 3000 行,却已经能在 Markdown、reStructuredText、HTML 和 LaTeX 之间互转。如今它支持五十多种输入格式和七十多种输出格式。加上 --pdf-engine=lualatex 就能经由 LaTeX 引擎一口气出 PDF,不过要注意:pandoc 不包含在 TeX Live 里。它是用 Haskell 写的独立程序,需要另行安装。

terminal
pandoc -f markdown -t latex in.md  -o out.tex    # Markdown to LaTeX
pandoc in.md  -o out.pdf --pdf-engine=lualatex  # Markdown straight to PDF
pandoc in.tex -o out.docx                       # LaTeX to Word
pandoc in.docx -o out.tex                       # Word to LaTeX

还有两个可以细致塑造输出的入口。--template 用来替换文本类输出格式(latexhtml 等)的外壳,可以换上你自己的导言区或 \documentclass。它对 .docx 这类二进制格式无效——那是上文 --reference-doc 的职责。另一个入口是 Lua 过滤器--lua-filter),它在读入之后、写出之前直接改写 AST。像「把某个环境改成另一种标题」「删掉所有 \todo{...}」这类活儿,放在这一步做,比用正则去改 LaTeX 源文件安全得多。

pandoc 读得懂哪些 LaTeX,读不懂时会不会警告

pandoc 只理解 LaTeX 的一部分,但也并非完全沉默。 遇到无法解析的公式时,它会打印 Could not convert TeX math 警告,并把该公式以 LaTeX 原样留在输出里——是原样传递,而不是丢弃。自定义宏的存活率也比想象中高:启用 latex_macros 扩展时,用官方手册的原话说,pandoc 会解析 LaTeX 的宏定义,并把得到的宏应用到所有 LaTeX 数学和生的 LaTeX 上。所以 \newcommand{\R}{\mathbb{R}} 这种程度是能通过的。真正悄无声息消失的是再往后的东西。被 pandoc 判定为生 LaTeX 的块(比如 tikzpicture 环境)会以 raw 形式保留在 AST 里,但 docx 和 HTML 的 writer 不会把它写出来。这时不像公式那样有警告,于是往往等到在 Word 里打开,才发现整张图不见了。

--reference-doc 决定 Word 的版面

当输出的 .docx 样子不对时,该动的不是模板,而是 --reference-doc。官方手册把机制讲得很明白:参考 docx 的内容会被忽略,只有它的样式表和文档属性——包括页边距、纸张大小、页眉和页脚——会用于新的 docx。 也就是说,参考文件是一份「空白的格式样本」,不是稿件模板。因此正确的做法是:先从 pandoc 取出默认参考文件,用 Word 或 LibreOffice 打开,把样式(Heading 1Body TextTable Caption 等)改成投稿规定要求的样子,保存后反复使用。手册还说,参考 docx 最好是由 pandoc 生成的 docx 改造而来。取出时要注意:-o 必须写在 --print-default-data-file 之前

terminal
# 1. extract the default reference file (-o must come first)
pandoc -o custom-reference.docx --print-default-data-file reference.docx

# 2. edit the STYLES in Word or LibreOffice, then save

# 3. reuse it for every export
pandoc in.tex -o out.docx --reference-doc=custom-reference.docx

Word → LaTeX 时真正管用的选项

.docx 实质上是一只装 XML 的 ZIP 压缩包,所以 pandoc 能直接读它。导入时第一个该加的开关是 --extract-media=media,它的作用正如官方手册所述:把文档中包含或链接的图片与媒体提取到指定目录,并把图片引用改写到提取出的文件上。忘了加,图就哪儿也不会出现。合作者退回来的文件常带修订记录,用 --track-changes=accept(接受)/reject(拒绝)/all(全部保留为 span)来决定怎么处理。这个选项只对 docx reader 生效。 文献可以用 --citeproc 配合 .bib 处理,CSL 样式用 --csl 指定。若嫌输出里段落被硬换行,加上 --wrap=none。Word 的段落样式会以 custom-style 保留下来,这正是把作者的自定义样式对应到 LaTeX 环境的线索。

terminal
pandoc in.docx -o out.tex \
  --extract-media=media \
  --track-changes=accept \
  --wrap=none

# with a bibliography and a journal style
pandoc in.docx -o out.tex --citeproc --bibliography=refs.bib --csl=apa.csl

不装 pandoc 也能交给 Word——tex4ht 的 ODT 输出

这一点少有人提:只用 TeX Live 也能输出到文字处理软件的格式。 运行 make4ht -f odt file.tex 会得到一个 .odt(OpenDocument 文本)。把它拆开看,会发现它并不是把图片拼上去了事——公式是以媒体类型 application/vnd.oasis.opendocument.formulaODF 公式对象嵌入的,里面装的是 MathML。也就是说,公式在文字处理端仍然是公式。mk4ht oolatex file.tex 走的是同一条路(旧文里会提到一个独立的 oolatex 命令;在 TeX Live 2024 中它是以 mk4ht 的作业名调用的)。Word 能打开 OpenDocument 文本;若想稳妥,可以用 LibreOffice 打开后另存为 .docx。当目的是把可编辑的公式交出去时,这条路的结果有时胜过 pandoc。

terminal
# LaTeX to OpenDocument text, using only TeX Live
make4ht -f odt file.tex

# the same route under its historical name
mk4ht oolatex file.tex

还有两个工具值得点名。writer2latex 是把 LibreOffice/OpenOffice 文档转成 LaTeX 的开源 Java 工具,GrindEQ 是商用的 Word ↔ LaTeX 转换器,以善于处理 MathType 公式著称。二者都不属于 TeX Live,撰写本文所用的机器上也没有安装,因此这里未验证其行为。若要采用,请先拿你真实文件的一小部分试一遍,亲眼确认公式和图形是否活了下来。

如何与坚持要 Word 的合作者共处

  • 以 LaTeX 为正本。 .docx 是输出,不是工作文件。一旦让 Word 里直接改过的版本成为主本,每一次往返都会开始劣化。
  • 按节交付,别整篇发。 只发想听意见的那一节,比发一个巨大的 .docx 更容易合并回来。
  • 收回来先用 --track-changes=all 读。 先看清改了什么,再用 accept 导入,或者只把修改手工誊回原文。
  • 图从一开始就用图片文件。 TikZ 经过 pandoc 会消失,所以把图导出成 SVG 或 PDF、用 \includegraphics 引入的结构,在每次转换中都不会坏。
  • 若要让对方能编辑公式,试试 ODT 路线。 make4ht -f odt 会把公式保留为 MathML 公式对象。
  • 把投稿规定封进 --reference-doc 每次在 Word 里手工调页边距和样式,第二次一定会忘。