作者:昇哥 & 易师 日期:2026-02-28 标签:
PandocXeLaTeX中文排版macOS隐私安全
一、为什么要折腾这套方案?
市面上能把 Markdown 转成 PDF 的工具多如牛毛:Typora、语雀、Notion、印象笔记…… 那为什么不直接用,非要自己折腾一套命令行方案?
答案只有两个字:隐私。
这篇文档的内容是个人思想体系的核心整理,包含大量私密的思考与沉淀。 任何"上传到某个服务器再导出"的方案,都意味着你的内容经过了别人的服务器, 存在被存储、被分析、甚至被泄露的风险。
本地方案的原则:
- 📴 全程离线,不经过任何第三方服务器
- 🔒 文件只在自己的机器上处理
- 🛠️ 完全可控,格式、字体、排版随心定制
这就是为什么我们选择了 Pandoc + XeLaTeX 这套纯本地的开源方案。
二、工具链介绍
| 工具 | 作用 |
|---|---|
| Pandoc | 万能文档转换器,将 Markdown 转为 LaTeX 中间格式 |
| XeLaTeX | 支持 Unicode 和中文的现代 LaTeX 引擎 |
| xeCJK | LaTeX 中文排版宏包,处理中文字体与断行 |
| Apple Symbols | macOS 内置字体,包含八卦等特殊 Unicode 符号字形 |
三、安装步骤
3.1 安装 Pandoc
macOS 上推荐用 Homebrew 安装:
brew install pandoc验证安装成功:
pandoc --version3.2 安装 XeLaTeX(MacTeX)
XeLaTeX 包含在 MacTeX 发行版中。由于体积较大(约 4GB),建议安装精简版 BasicTeX:
brew install --cask basictex安装完成后,刷新环境变量:
eval "$(/usr/libexec/path_helper)"验证安装:
xelatex --version3.3 安装必要的 LaTeX 宏包
BasicTeX 不含所有宏包,需要手动补充:
sudo tlmgr update --self
sudo tlmgr install xecjk collection-fontsrecommended四、第一次尝试:只用 Pandoc,失败了
安装好 Pandoc 后,第一反应是直接用最简单的命令转换:
pandoc 《Dao核心理论》.md -o dao.pdf结果:失败。 报错信息大意是找不到合适的 PDF 引擎。
于是指定引擎:
pandoc 《Dao核心理论》.md -o dao.pdf --pdf-engine=xelatex这次生成了 PDF,但打开一看——问题一大堆:
- 中文正常显示,但数学公式里的中文全部消失
- 八卦符号(☵☴☳☶☷☱☲☰)全部变成空方块
□ - 排版比较粗糙,页边距过大
光靠一行命令是不够的,需要一个专门的 LaTeX 配置文件来处理这些问题。
五、踩坑记录与解决过程
坑一:数学公式中的中文丢失
现象: 编译后 PDF 中,数学公式里的中文字符全部消失,只剩下英文和符号。
% 期望显示:
$$Dao = Fn_{现代思维解读}(...)$$
% 实际显示:
$$Dao = Fn_{}(...)$$ ← 中文消失了原因:xeCJK 宏包默认不介入数学环境,数学模式下的 CJK 字符会被直接忽略。
解决方案: 创建 dao-header.tex 配置文件,加入以下设置:
\usepackage{xeCJK}
\xeCJKsetup{CJKmath=true} ← 这一行是关键CJKmath=true 告诉 xeCJK:数学环境里的中文也要正常渲染。加上这行后,公式中的中文全部恢复正常。
坑二:八卦符号显示为方块(□□)
现象: 文档中精心挑选的八卦符号 ☵☴☳☶☷☱☲☰,在 PDF 里全部变成了难看的空方块。
原因: 主字体宋体(Songti SC)的字形库里根本没有这些 Unicode 符号(U+2630–U+2637), XeLaTeX 找不到字形,只好用方块占位。
排查过程:
先确认系统里有没有包含这些字符的字体:
fc-list | grep -i "apple symbols"
# → /System/Library/Fonts/Apple Symbols.ttf: Apple Symbols:style=Regular再确认字符本身没问题(是字体问题,不是编码问题):
python3 -c "print('☵☴☳☶☷☱☲☰')"
# → ☵☴☳☶☷☱☲☰ ✅ 终端正常显示结论: macOS 内置的 Apple Symbols 字体包含这些字符,只需要让 XeLaTeX 在遇到这些字符时自动切换字体即可。
解决方案: 使用 XeTeX 的 interchar 机制,为 U+2630–U+2637 范围自动切换字体:
\newfontfamily\AppleSymbols{Apple Symbols}
\XeTeXinterchartokenstate=1
\newXeTeXintercharclass\SymClass
\XeTeXcharclass"2630=\SymClass
\XeTeXcharclass"2631=\SymClass
\XeTeXcharclass"2632=\SymClass
\XeTeXcharclass"2633=\SymClass
\XeTeXcharclass"2634=\SymClass
\XeTeXcharclass"2635=\SymClass
\XeTeXcharclass"2636=\SymClass
\XeTeXcharclass"2637=\SymClass
\XeTeXinterchartoks 0 \SymClass = {\begingroup\AppleSymbols}
\XeTeXinterchartoks \SymClass 0 = {\endgroup}这段配置的意思是:凡是遇到 U+2630–U+2637 范围内的字符,自动用 Apple Symbols 字体渲染,渲染完再切回主字体。
坑三:\sym 未定义报错
现象: 加上字体配置后重新编译,又报了新错误:
! Undefined control sequence.
<argument> 上坎下巽,水风井(\sym
{☵☴})
l.1116 易师的基因,是一个卦象:\textbf{上坎下巽,水风井(\sym{☵☴})}原因:.md 文件里有些地方用了 \sym{☵☴} 这个自定义命令来手动指定符号字体, 但 dao-header.tex 里只配置了字体,忘记定义 \sym 命令本身。
解决方案: 在配置文件中补充一行命令定义:
\newcommand{\sym}[1]{{\AppleSymbols #1}}这样 \sym{☵☴} 就等价于 {\AppleSymbols ☵☴},用 Apple Symbols 字体渲染符号。
六、最终完整方案
dao-header.tex
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{xeCJK}
\usepackage{fontspec}
% 中文字体设置
\setCJKmainfont{Songti SC}
\setCJKsansfont{PingFang SC}
\setCJKmonofont{Heiti SC}
% 允许数学环境中使用中文
\xeCJKsetup{CJKmath=true}
% 八卦符号字体
\newfontfamily\AppleSymbols{Apple Symbols}
% 定义 \sym 命令,用于在正文中手动指定符号字体
\newcommand{\sym}[1]{{\AppleSymbols #1}}
% 自动让八卦符号 U+2630–U+2637 走 Apple Symbols 字体
\XeTeXinterchartokenstate=1
\newXeTeXintercharclass\SymClass
\XeTeXcharclass"2630=\SymClass
\XeTeXcharclass"2631=\SymClass
\XeTeXcharclass"2632=\SymClass
\XeTeXcharclass"2633=\SymClass
\XeTeXcharclass"2634=\SymClass
\XeTeXcharclass"2635=\SymClass
\XeTeXcharclass"2636=\SymClass
\XeTeXcharclass"2637=\SymClass
\XeTeXinterchartoks 0 \SymClass = {\begingroup\AppleSymbols}
\XeTeXinterchartoks \SymClass 0 = {\endgroup}Pandoc 转换命令
pandoc 《Dao核心理论》.md -o dao.pdf \
--pdf-engine=xelatex \
-V mainfont="Songti SC" \
-V CJKmainfont="Songti SC" \
-H ~/dao-header.tex \
-V geometry:margin=2.5cm运行后,PDF 顺利生成,中文、公式、八卦符号全部正确渲染 ✅
七、经验总结
| 场景 | 解决方案 |
|---|---|
| 中文在数学公式中丢失 | \xeCJKsetup{CJKmath=true} |
| 特殊 Unicode 符号显示方块 | XeTeXinterchar 机制 + 备用字体 |
| 自定义 LaTeX 命令未定义 | 在 header 文件中用 \newcommand 定义 |
| 验证字体是否包含某字符 | fc-list + python3 -c "print(...)" |
💡 核心思路: XeLaTeX 的字体回退机制不是自动的,需要手动为特定 Unicode 范围指定备用字体。 遇到方块问题,第一步永远是先确认字体是否包含该字符,再考虑如何切换字体。
八、写在最后
这套方案看起来比点几下按钮麻烦多了,但它换来的是:
- 你的文字,只在你的机器上流动
- 没有账号,没有云端,没有第三方
- 一次配置,永久可用
对于承载个人核心思想的文档来说,这点折腾,值得。
参考资料
- Pandoc 官方文档
- xeCJK 宏包文档
- XeTeX interchar 机制
- Unicode 八卦符号范围:
U+2630–U+2637(八卦)、U+4DC0–U+4DFF(六十四卦)
- 本文链接:https://fridolph.top/posts/2026-02-28__pandoc
- 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 许可协议。