Files.md如何手写Markdown解析器放弃AST后代码量减少3倍的实战【免费下载链接】files.md Private, quiet space for thinking. Simple app for .md files.项目地址: https://gitcode.com/GitHub_Trending/fi/files.mdFiles.md 是一个本地优先、纯.md文件驱动的笔记应用私有、安静的思考空间。本文分享它在手写 Markdown 解析器上的实战经验当年放弃通用的 AST抽象语法树方案后解析代码量直接减少 3 倍理解和维护的心智负担也随之大幅下降。这是一个少即是多的典型工程决策。 为什么放弃 AST边界情况太多认知负荷太重很多开发者处理 Markdown 时的第一反应是引入成熟解析库把文本解析成 AST再遍历节点渲染成 HTML。这条路在 Files.md 上也走过但很快被放弃原因写在了项目的架构决策记录ADR里走 AST 时遇到太多边界情况代码也愈发复杂。Markdown 并不那么难解析老老实实写直白的代码就好。最终代码量降到原来的 1/3理解起来也轻松多了。—— README.md核心矛盾在于你只需要支持自己业务用到的那一点点语法子集加粗、斜体、代码块、链接、清单却要承担整套 AST 机制带来的复杂度。对一个人或一个 LLM就能装进脑子里的小项目来说这是典型的过度设计。✂️ 手写解析的核心思路只做字符串到字符串的直白转换Files.md 的服务端用 Go 编写Markdown 处理全部集中在 server/pkg/txt/md.go 中。它的哲学可以概括为一句话不建树直接变换字符串。以 server/pkg/txt/md.go 中的MarkdownToHTML为例它要把用户的 Markdown 转成 Telegram 支持的那一小撮 HTML 标签。整个流程只有四步全部是正则 字符串替换先转义 HTML避免用户的破坏输出用占位符把代码块和行内代码临时替换掉占位符写成c0debl0ck、inl1ne这种不会自然出现的字符串保护它们不被后续转换误伤按空行\n{2,}切段对每段跑一个轻量级的手写解析器处理加粗、斜体恢复占位符再用正则把代码块、标题补上pre、code、b标签。代码注释里写得很直白We dont need to implement full-blown AST parser because TG only supports a few HTML tags.我们不需要实现完整的 AST 解析器因为 Telegram 只支持少数 HTML 标签。—— server/pkg/txt/md.go这就是手写解析器最重要的原则按需求的天花板来设计。你不需要解析完整 CommonMark你只需要解析业务真正用到的那一小部分。 轻量手写解析器用解析器组合子拼出语法server/pkg/txt/md.go 里有一个不到百行的迷你解析器没有 AST、没有节点对象核心类型只是一个函数type parser func(input string) []result每个解析器吃进一段字符串吐出已消费的部分 剩余的部分。在此之上只用三个组合子拼出全部语法and(a, b, c)按顺序依次匹配or(a, b)任一匹配即可some(p)重复匹配。于是加粗、斜体的语法树其实是函数嵌套就是几行声明式的拼装比如加粗 ** 若干(文本或斜体) **。项目明确只支持一层嵌套见 server/pkg/txt/md.go 注释因为笔记场景里两层以上的嵌套加粗几乎没有价值——主动砍掉语法代码自然简单。 反向转换也手写Telegram 实体 → Markdown解析器是双向的。用户在 Telegram Bot 里发的加粗、斜体消息需要还原成 Markdown 存进文件。这个逆向转换在 server/pkg/txt/tgtxt.go 中完成遍历 Telegram 的 message entities计算 UTF-16 偏移把**、*、等标记精确地插回文本里。同样是逐字符的直白逻辑没有引入任何第三方 Markdown 库。 前端同款思路逐行处理不引入任何构建浏览器端同样贯彻手写路线。web/lib/md.js 顶部的注释写着Various string functions, ported from Golang bot——前端逻辑就是从服务端逐字移植过去的。比如 web/lib/md.js 的extractHeaderAndBody取第一行做标题、截断过长标题、去重标题全靠split(\n) 前缀判断十几行解决从一段文本里提取标题这种 AST 方案里需要好几个节点遍历器才能做的事。更关键的是这种手写代码是双向可维护的改服务端的清单逻辑前端的移植版本几乎一比一对应新人读代码时所见即所得没有任何抽象层。 实战收益代码量减 3 倍理解成本大幅下降这次重构带来的直接收益项目 ADR 总结得很清楚维度AST 方案手写方案代码量基线约 1/3边界情况节点遍历的组合爆炸正则前缀匹配一眼看穿依赖引入成熟大库零依赖纯正则与字符串扩展方式写节点访问器加一个组合子或一条正则配套的原则也写进了 ADRTolerant Reader遇到乱码就跳过遇到有效标志如###但数据无效则明确报错。容错策略同样简单直接例如 server/habits/habits.go 解析习惯文件时逐行校验月标题失败就返回带上下文的错误。 小结什么时候该手写解析器Files.md 的经验可以浓缩成三条判断标准你的语法子集足够小——只处理加粗、斜体、代码块、清单就不需要通用 AST你要双向转换——Markdown ↔ 目标格式HTML、Telegram 实体都能用字符串进、字符串出的函数表达维护者是一个人 LLM——直白的代码能被完整装进工作记忆改一行不会牵动整个解析树。如果你的场景是渲染任意用户提交的复杂文档完整表格、嵌套列表、脚注成熟解析库仍是正解但如果是 Files.md 这种自己掌控输入格式的本地优先应用手写那个刚刚好的解析器往往比引入大轮子更省钱、更耐用。 延伸阅读docs/sync-flow.md 了解这些.md文件如何在设备间同步web/lib/md.js 可直接对照服务端 server/pkg/txt/md.go 阅读。【免费下载链接】files.md Private, quiet space for thinking. Simple app for .md files.项目地址: https://gitcode.com/GitHub_Trending/fi/files.md创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考