起因是本人喜欢在写博客的时候尽量带上目录,可以让整体的结构和思路更加清晰。

但是博客自带的 Markdown 解析库并不是那么好用,虽然能满足基本功能,但是在拓展性上不是很友好。

曾经自己 hook 源代码来实现 TOC 语法,无奈很不优雅,每次升级做 merge 也是很麻烦的事情。

所以干脆整个插件,自己动手,丰衣足食。

自己再去造一个 Markdown 解析器的轮子很显然不合适。于是网上 github 搜索一波,其实 PHP 版本的 Markdown 解析器还真不多。

根据 star 数、活跃度、issue 情况,综合评定下来选择了 erusev/parsedown

关于TOC的支持,目前并没有解决方案。作者 erusev 在这个 issues 上回答了,其并没有打算支持,所以我只能自己来了。

1.0.1

然后有了第一版的 Markdown 解析插件:mrgeneralgoo/typecho-markdown(1.0.1)

这版本主要是干了俩件事:

1.更换 Markdown 解析库,在性能和可拓展性上有较大的提升。

2.新增TOC语法支持。

TOC的支持实现上是通过 DOMDocument来操作解析完后的 DOM 元素,然后添加目录元素到 HTML 里面。这个操作会把 HTML 源码转成 NCR 格式,不方便阅读,但也是 HTML 规范之一,不影响使用。

经过自己使用一个月后很稳定,于是开源出来了。但是其他人使用会出现一些问题,比如在某些场景下会出现乱码

这个可能是DOMDocument处理内容的时候遇到了特殊的字符串处理出现了问题。

虽然采用了处理 DOM 这种通用且暴力的方案,但是后来我发现就 Markdown 生成目录来说,并不需要这种通用的操作方式,只针对 Markdown 处理就好了。

1.1.0

所以这次有了第二版 Markdown 解析插件:mrgeneralgoo/typecho-markdown(1.1.0)

这次主要变更如下:

1.精简结构,移除暂时无用的 erusev/parsedown-extra

2.优化性能,解决乱码问题,使用原生 Markdown 语法来实现目录生成。

3.把TOC解析的逻辑拆分出来,做成了一个单独的 parsedown-extension 库

新版本,性能提升近 20%,并且源码不会再被转成 NCR 格式,乱码问题也被彻底解决。

当然过程中也比较坎坷曲折。

第一就是 erusev/parsedown 很不规范,而且文档也少,大部分情况下只能通过作者自己开发的 erusev/parsedown-extra 来学习,推导如何接入,学习成本很高。

第二是 erusev/parsedown 在代码设计上对拓展并不开放,只适合用来做基类。比如我这里实现了TOC语法,你实现了LaTeX语法,但是我们俩的代码是不能直接一起使用的。得通过 merge 代码的方式,把功能都集成到一个子类当中才行,要是想像一个插件一样安装即用是不可能的。

我也明白,为什么 joyqi 要自己写一个 Markdown 解析器 SegmentFault/HyperDown 了。

Markdown已经面世许多年了,国内外许多大大小小的网站都在用它,但是它的解析器却依然混乱不堪。SegmentFault 是中国较大规模使用 Markdown 语法的网站,我们一直在使用一些开源类库,包括但不限于

  1. php-markdown
  2. CommonMark for PHP
  3. Parsedown

他们都有或多或少的毛病,有的性能较差,有的代码比较业余,更多的情况是由于Markdown本身解析比较复杂,因此我们几乎无法去维护另外一个人写的代码。基于这个原因,我为 SegmentFault 专门编写了这么一个Markdown解析器。

当然,其实有很多设计模式解决第二点,不过鉴于目前还不需要这样做,如果有需要,我还是会尝试一下的😏。

本文由程小白创作,本文可自由转载、引用,但需署名作者且注明文章出处。

原文地址:https://www.chengxiaobai.cn/php/markdown-parser-library.html