信创环境下WordPress公式兼容:Pandoc+MathJax批量转换方案
1. 先把问题拆透公式兼容卡在哪一步1.1 信创环境下的WordPress部署栈提到信创环境很多人第一反应就是国产服务器、国产操作系统、国产数据库但落到实际部署时真正影响公式兼容问题的往往是这三层第一层是操作系统与CPU架构。现在常见的信创服务器大多是麒麟操作系统银河麒麟、中标麒麟、统信UOS配上飞腾、鲲鹏、龙芯、海光或者兆芯处理器ARM架构占了大头。这意味着很多在X86 Windows上跑得好好的软件、编译好的二进制包都可能需要重新编译或者找对应的ARM版本这就是公式处理工具链上容易卡壳的地方。第二层是Web运行环境。WordPress是PHP项目在信创环境里最常见的组合是Nginx PHP-FPM MariaDB有时候也会要求适配达梦、人大金仓这样的国产数据库。PHP的版本高低直接影响插件兼容性比如老版本的MathJax插件可能在PHP 8.0以上直接报错这些都要提前摸底。第三层是网络环境。我接触的多数信创项目都是内网或政务外网环境访问不了公网CDN这意味着依赖CDN加载JavaScript资源的方案统统要打回重做必须把MathJax等前端渲染库完整下载到本地服务器走静态资源路径。这三层叠加起来公式兼容问题就不只是Word和网页格式不一样这么简单了而是一个从文档转换工具到服务器运行环境再到前端渲染的完整链路问题。1.2 公式格式的方言与普通话先把公式格式这个事说清楚。微软Word里录入公式时默认保存的格式叫OMMLOffice Math Markup Language这是Office自己的一套数学公式XML描述语言。问题是这套格式只有微软Office认识你在WordPress的古腾堡编辑器里直接粘贴公式它不认识OMML就会把公式显示成一堆乱糟糟的XML标签或者干脆变成图片样式丢失的空对象。网页端几大主流公式语言实际上是这两种MathMLW3C标准推荐的网页数学标记语言类似于普通话理论上浏览器原生支持但实际各浏览器支持程度参差不齐。LaTeX理工科写论文最常用的公式语法MathJax这个JavaScript库可以在网页端把LaTeX渲染成漂亮的公式是WordPress生态中应用最广泛的方案。所以问题的本质就一句话把Word公式这个微软方言翻译成网页能看懂的标准语言翻译的过程中还要保证符号、结构、排版不丢不坏。转换路径一般有三种OMML转MathML、OMML转LaTeX、OMML转图片。每条的优缺点在下一节展开。1.3 三条路线的整体对比在动工之前先把三条技术路线的适用场景、转换精度、后期维护成本放一起对比这样大家可以根据自己的实际内容量来选择不用三条路子都踩一遍。方案转换方式转换精度维护成本推荐场景方案APandoc将docx转为Markdown/HTML公式转LaTeX前端用MathJax渲染高公式结构完整低一次性转换后无需再次处理批量文章导入、长期维护的内容站方案BWord内部公式直接复制为MathML粘贴进编辑器MathJax渲染中高依赖Word版本和浏览器剪贴板中每篇手动操作少量文档、临时发布方案C公式截图或导出为图片在WordPress中当作图片插入最高所见即所得高后期改公式要重新截图图片型公式站、公式中带复杂特殊符号的场景三条路线各有适用场景但绝大多数内容迁移场景下方案A的性价比最高也是这篇文章的主角。如果文章数量不多比如十篇以内且公式不复杂方案B可以省掉很多工具链的折腾如果公式里含有大量特殊符号、矩阵、括号套娃方案C的图片兜底最稳妥。2. 主力方案Pandoc批量转换Word公式MathJax前端渲染2.1 在信创服务器上安装PandocPandoc是一个万能文档转换工具支持docx转Markdown、HTML、LaTeX等几十种格式。对公式处理来说Pandoc最关键的能力是能把Word的OMML公式自动提取出来并转为LaTeX表达式。安装方面如果麒麟或统信系统的软件仓库里有Pandoc直接# 在麒麟OS/统信UOS上 sudo apt update sudo apt install pandoc但很多内网环境的软件仓库版本比较老可能还是Pandoc 2.x或者压根没收录这时候建议直接从Pandoc官方GitHub Release页面下载对应架构的Linux压缩包。注意看一下CPU架构飞腾、鲲鹏下载aarch64版本海光、兆芯下载amd64版本龙芯要看具体的ABI类型通常下载loongarch64版本。# 例如在鲲鹏/飞腾服务器上 wget https://github.com/jgm/pandoc/releases/download/3.1.11/pandoc-3.1.11-linux-arm64.tar.gz tar xzf pandoc-3.1.11-linux-arm64.tar.gz sudo cp pandoc-3.1.11/bin/pandoc /usr/local/bin/ pandoc --version注意Pandoc 3.x和2.x在公式处理的行为上有些差别转换结果以自己实测为准。如果3.x转换出来的公式有异常可以退回2.19试试很多老项目至今钉在2.x版本不是没有原因的。2.2 目标格式选择与转换命令Pandoc支持把docx转成Markdown或HTML区别在于公式的包裹语法不同。转Markdown时推荐加上tex_math_dollars扩展公式会被写成$...$和$$...$$形式这是MathJax最通用的输入格式pandoc input.docx -f docx -t markdowntex_math_dollars -o output.md转HTML时公式则默认写成\(...\)和\[...\]形式如果显式指定--mathjax参数pandoc input.docx -f docx -t html --mathjax -o output.html如果你打算把内容直接贴进古腾堡编辑器的HTML模式推荐直接转HTML如果你想把文章导入到某个支持Markdown的WordPress主题或者用插件比如WordPress自带或第三方Markdown插件来管理内容转Markdown更方便。转换完成后务必抽查几篇公式密集的文章。我第一次批量转换时发现有的公式里的根号、积分符号转换正常但上下标偶尔会形成错误的嵌套结构这种问题必须人工抽检才能发现。2.3 转换后的内容清洗与公式校验Pandoc不是万能的转换过程中会出现一些需要人工清洗的边角料常见的有这么几类。第一类是Word特殊字符比如自动编号、交叉引用、页眉页脚的内容不会进入转换结果这没问题。但文档里的公式编号类似1.1这种往往还留在文本中有些是Word域代码有些是普通文本Pandoc不一定能一致地转换。我通常的做法是转换后写个简单的Python脚本正则匹配公式行内的编号位置统一挪到行尾。import re, glob for md_file in glob.glob(output/*.md): with open(md_file, r, encodingutf-8) as f: content f.read() # 形如 $$ ... (1.1) $$ 的公式编号挪到公式外面 content re.sub(r\$\$([^\$]?)\\tag\{([^\}])\}\$\$, r\n\n$$\1$$\n\n\2\n\n, content) with open(md_file, w, encodingutf-8) as f: f.write(content)第二类是从Word粘贴时残留的隐藏字符和空格。Word里的全角空格、不间断空格在Markdown中不会显示错误但复制到编辑器后可能造成排版异常。清洗姿势用sed或者脚本把\u00a0不间断空格替换成普通空格。第三类是公式内部的LaTeX校验。MathJax渲染宽容度很高但遇到老旧Word版本转换出的公式仍可能报错常见错误是\left和\right不配对、\begin{matrix}缺少\end{matrix}。可以在浏览器里逐个打开文章检查也可以用MathJax在服务端配合Puppeteer做批量渲染测试但那个成本稍高日常人工抽查就足够。2.4 在WordPress里接入MathJax渲染公式转换好了接下来就是让WordPress前端把LaTeX渲染出来。最省事的方式是用插件在WordPress插件市场搜索MathJax比较常用的有MathJax-LaTeX、WP QuickLaTeX、Simple MathJax。插件的配置画面都差不多重点设置两个地方TeX输入配置确保inlineMath包含$...$displayMath包含$$...$$。很多插件默认只识别\(...\)要手动把美元符号加进去。MathJax { tex: { inlineMath: [[$, $], [\\(, \\)]], displayMath: [[$$, $$], [\\[, \\]]] } };加载地址内网环境一定不能选CDN要把MathJax的静态文件下载到本地然后在插件设置里把URL改成本地路径。下载地址是MathJax官方GitHub的release包解压到WordPress的wp-content/uploads/mathjax目录即可。如果你的WordPress主题比较干净不想多装插件也可以直接在主题的footer.php里手动引入MathJax脚本script window.MathJax { tex: { inlineMath: [[$, $]], displayMath: [[$$, $$]] } }; /script script src?php echo wp_upload_dir()[baseurl]; ?/mathjax/tex-mml-chtml.js async/script注意古腾堡编辑器有时会自动把$符号转换成HTML实体$导致MathJax识别不了。如果发现公式渲染不出来在编辑器里切到自定义HTML模式检查一下公式代码外层有没有被套上了code标签或者被转义。3. 备用方案Word内直接复制MathML快速发布少量公式文章3.1 Word公式转MathML的两种操作路径如果只是偶尔发一两篇带公式的文章没必要专门搭Pandoc的转换环境直接在Word里把公式转成MathML再贴到WordPress里就行。这里有两个路径可以试。路径一是利用Word的另存为功能。对docx文档另存为网页*.htm然后用文本编辑器打开生成的HTML文件里面会有完整的MathML代码公式都在math标签里。把这段代码复制到古腾堡的自定义HTML区块即可。路径二是直接复制粘贴。在较新版本的WordOffice 2019、Office 365中选中公式后直接复制粘贴到网页端支持MathML的编辑器时剪贴板里会自动带上MathML格式。但在信创环境里如果用的是WPS Office这个功能可能不完整。我实测时发现WPS复制公式粘贴到网页里得到的是一张图片或者纯文本这种情况下只能靠路径一。复制过来的MathML不一定干净还需要做一步检查很多版本会把命名空间声明xmlns:mmlhttp://www.w3.org/1998/Math/MathML也带进来在HTML5页面里这种命名空间容易触发解析警告建议去掉只保留标准math标签结构。3.2 WordPress前端的MathML渲染配置MathJax天然支持MathML输入所以接入方式和LaTeX几乎一样。区别在于MathJax的startup配置里要让input包含mathmlwindow.MathJax { loader: {load: [input/mml, output/chtml]} };如果站点同时有LaTeX和MathML格式的公式建议统一用MathJax把它们渲染成HTMLCSS输出这样视觉风格一致不会出现有些公式是矢量渲染有些公式是浏览器原生MathML的割裂感。实测下来Firefox和Chrome对MathML的支持程度不同Firefox对新版MathML Core支持得更好Chrome需要依赖MathJax的polyfill能力才能完整渲染。所以后端务必保留MathJax作为兜底渲染器不要试图依赖浏览器原生MathML能力。4. 兜底方案公式转高清图片特定场景下最稳的选择4.1 图片方案的适用场景虽然前两套方案能覆盖90%以上的需求但有些场景是绕不开图片的。我遇到过的典型情况包括公式里带有Word专有的字符比如某些特殊符号通过公式域编码呈现Pandoc转换后变成了乱码。公式中包含矩阵、分段函数、多行公式嵌套转换后结构混乱人工修正成本比截图还高。图片型OCR结果上游文档就是扫描版或者低质量截图根本不存在可复制的OMML公式。在这些情况下与其跟格式硬刚不如直接用图片方案把公式变成高分辨率图片贴进WordPress至少保证排版和内容不出错。4.2 用LibreOffice和PDF渲染公式图片的流水线信创环境里通常会预装或者可以安装LibreOffice它在X86和ARM架构下都有官方支持。一个稳定可靠的公式图片生成流程在我的实践里是这么走的第一步把Word文档用LibreOffice批量转成PDFsoffice --headless --convert-to pdf input.docx第二步在PDF中定位到公式所在的页面用pdftoppmpoppler-utils把页面渲染成300dpi以上的PNG图片pdftoppm -png -r 300 input.pdf page第三步用图形工具GIMP、Krita或者Python脚本把公式区域裁剪出来。如果公式位置固定可以用pdfcrop工具直接裁剪。关于清晰度我的建议是网页端图片不需要太大但公式这种细节密集的内容宽度至少600px字号渲染出来跟正文匹配最好。300dpi渲染出来的公式图片如果原PDF清晰效果完全够用。第四步WordPress上传图片在文章中插入图片时记得加上alt文本比如公式-麦克斯韦方程组方便后面搜索和SEO。这个流程胜在稳定缺点是每次改公式都要重新导出。所以我只建议把它作为兜底方案顶多放在转换流水线的最后一道防线上。5. 信创环境下的部署适配与实操细节5.1 MathJax本地化的完整放置前面提到内网环境不能依赖CDN但MathJax的本地化部署不只是把文件拷贝到服务器那么简单。MathJax 3.x版本在浏览器端会动态请求字体文件、组件文件如果你直接把整个mathjax目录丢到wp-content/uploads下Nginx可能因为路径权限问题导致字体加载404。推荐的做法是把MathJax放到WordPress主题目录下的assets/mathjax里并在Nginx站点配置中单独放行静态文件请求location ~ ^/wp-content/themes/your-theme/assets/mathjax/ { expires 30d; add_header Cache-Control public; try_files $uri 404; }这样既保证了加载速度又避免了权限问题。同时记得检查PHP上传限制如果你的MathJax包是压缩上传到服务器解压的注意upload_max_filesize和post_max_size这两个参数默认2M可能不够用。5.2 PHP版本与插件兼容性处理信创服务器上常见的PHP版本从7.4到8.2都有。老的WordPress版本在PHP 8.0以上可能产生弃用警告MathJax插件更是重灾区。我遇到过的情况是插件后台设置页能打开但前端无法加载MathJax脚本打开F12看控制台全是Deprecated: Function ereg() is deprecated之类的报错——这是因为有些老插件还在用PHP 7时代废弃的函数。解决思路尽量选仍在维护的插件比如MathJax-LaTeX的更新频率还可以。如果插件确实不更新了手动接MathJax脚本是最干净的方案直接改主题的functions.php把脚本注入到文章页。function my_mathjax_assets() { if (is_singular()) { echo scriptwindow.MathJax {tex: {inlineMath: [[$, $]]}};/script; echo script src . get_template_directory_uri() . /assets/mathjax/tex-mml-chtml.js async/script; } } add_action(wp_footer, my_mathjax_assets);这样绕开了插件的兼容性问题也减小了攻击面在内网环境反而更省心。5.3 数据库层的适配提醒虽然WordPress官方只支持MySQL和MariaDB但信创项目经常会强制要求使用达梦或者人大金仓数据库。如果你的项目明确要使用国产数据库我的建议是先确认是否支持WordPress的插件桥接层达梦有MySQL兼容模式但是WordPress的wp_options表等使用习惯在兼容模式下仍然可能有坑比如序列化和JSON字段的处理差异。公式转换这个环节本身不涉及数据库层但你的文章内容包含LaTeX源码、MathML最终会存到数据库里。LaTeX源码中含有反斜杠、花括号、美元符号如果在导入时经过了一遍数据库转义很容易出现反斜杠消失、公式报错的情况。所以数据库存储层的字符集必须是utf8mb4否则特殊符号在MySQL里会炸。查看一下当前数据库字符集SHOW VARIABLES LIKE character_set_database; SHOW VARIABLES LIKE collation_database;如果不是utf8mb4需要在wp-config.php里加上一行强制字符集设置define(DB_CHARSET, utf8mb4); define(DB_COLLATE, utf8mb4_unicode_ci);这个细节在做公式迁移时特别容易忽视等公式贴进去变成问号再排查就是好几天的工时成本了。6. 常见问题速查表与踩坑记录6.1 高频问题速查表把我在实际项目中遇到的高频问题整理成了表格方便大家直接对照排查。问题现象可能原因解决办法公式在后台编辑正常前台不渲染MathJax脚本未加载或配置里未启用$分隔符检查网络请求确认MathJax本地路径配置确认inlineMath包含$...$转换出来的公式是\[和\]MathJax不识别Pandoc转HTML默认输出LaTeX环境MathJax未启用对应解析在MathJax配置里加上displayMath: [[$$, $$], [\\[, \\]]]导入后公式变成一堆math标签源码网站后台关闭了HTML标签解析或使用了富文本编辑模式切到自定义HTML模式粘贴检查古腾堡是否过滤了math标签必要时用wp_kses_allowed_html扩展白名单图片型公式放大后模糊导出分辨率不足用300dpi以上渲染或直接复制Word里公式的矢量图EMF转SVG公式里的中文注释变成乱码字体缺失或字符集不对数据库字符集确认utf8mb4Word转出时检查字体名称映射尤其注意黑体、宋体在信创系统中的替代MathJax在无外网环境一直转圈浏览器尝试加载CDN中的字体文件部署MathJax时确保fontURL指向本地路径或使用tex-svg.js版本并内嵌字体WordPress文章页面会显示$符号但公式不渲染编辑器自动转义美元符号检查编辑器是否把$转为$在自定义HTML区块手工修正或用MathJax的tex2jax配置处理$转义6.2 几个值得单独说的坑第一个坑是古腾堡编辑器的代码区块陷阱。当公式包含大量$和反斜杠时古腾堡有时候会自动判断为代码把它包进code标签。MathJax默认不渲染code里的内容所以公式死活不显示。解决方式很简单公式段落不要用代码区块一律用段落或者自定义HTML区块粘贴前先在记事本里过一遍确保没有隐藏的HTML实体。第二个坑是Markdown插件与MathJax的先后加载顺序。如果站点同时开启了Markdown插件和MathJax插件Markdown插件会把$...$误判成Markdown的行内代码标记提前包裹成code导致MathJax二次处理时直接跳过。解决办法是调整两个插件的加载顺序让Markdown解析先于MathJax渲染或者干脆用Pandoc转出的纯HTML内容不再经过Markdown解析。第三个坑是批量转换时公式编号的处理。Word文档里公式编号如果用制表符文本的形式还好办但如果是用公式编号域插入的Pandoc默认会当成普通文本处理位置和格式都错乱。我后来写了个前置清理脚本在转换前先删除Word文档里所有公式编号域保留纯文本内容再用正则统一补编号位置整个过程跑通后效率大幅提升。6.3 个人使用体会公式兼容问题在信创环境下绕了一圈归根到底还是格式生态的问题。Word公式本身是一个封闭但友好的格式把它迁移到WordPress这个开放生态里总要经历一次格式翻译。PandocMathJax这条路在我实操下来最稳关键在于转换后的抽检不能省尤其是矩阵、分段函数、复杂上下标这些结构密集的公式抽查时间和转换时间持平都是正常的。如果你跟我的情况类似——几十上百篇带公式的历史文档需要迁移到信创环境中的WordPress站点优先走Pandoc批量转换路线所有工具都可以在纯内网环境里部署完成无需外网依赖。内容量少于十篇则直接用Word复制MathML的方式更快公式图片方案留在最后兜底就好。