有许多因素会导致 Markdown 解析器的复杂性。也就是说,您可以使用“简单的基于正则表达式”的方法来构建 Markdown 解析器。事实上,这正是参考实现所使用的(在 Perl 中)。它运行一系列正则表达式,将现有文档上的 Markdown 语法替换为 HTML 语法。即使这样,源代码也由 1451 行代码组成,包括注释、许可证等。当然,它包括对原始语法规则中描述的整个功能列表的支持。这些功能包括对嵌套、转义等的支持,这使正则表达式的使用变得非常复杂。
一些人发现这样的实现限制。这一切都取决于你想从 Markdown 解析器中得到什么。
例如,使用参考实现几乎不可能扩展语法。例如,Python-Markdown(我是其中的开发人员)采用了参考实现,为每个正则表达式命名,并为第三方扩展提供了一种方法来替换或插入新的正则表达式。样板代码只是为了允许这样做添加了相当多的代码行。顺便说一句,Markdown 已经过时了,像 Python-Markdown 这样的库多年来已经发生了变化和发展。第一个版本非常接近地模仿了参考实现,但今天你很难看到它们之间有任何相似之处。
其他人对扩展语法并不感兴趣,而是对提供一种控制输出的方法感兴趣。例如,标记的JS 库输出一个抽象语法树 (AST),然后可以将其传递给渲染器。渲染器接受 AST(基本上是令牌列表)并输出其他格式。其他格式可以是 HTML,也可以是其他格式。Pandoc利用这一点来转换多种文档格式。自然,这会增加额外的代码行。
另一个因素,无论是否实现,许多人会争辩说,如果一个实现不支持规则中的所有功能,那么它就不是 Markdown。事实上,多年来,许多实现都添加了非标准特性(以 GitHub Flavored Markdown 为例)。人们开始依赖这些非标准特性,并会提交错误报告,抱怨实现不支持它们。作为 Python-Markdown 的开发人员,当 lib 实际上提供支持时,我经常会看到此类报告。它只是默认情况下未启用。当向他们指出这一点时,他们的反应往往不如理解。因此,如果不支持所有标准功能,任何针对一般消费的实现都不会持续很长时间。
增加额外的复杂性是在标准特性的实现之间没有完美的协议。有关详细信息,请参阅Babelmark 2 常见问题解答。在该常见问题解答中,您会发现许多记录在案的差异非常细微。人们确实发现这些细微差别很重要。为此,一群人创建了Commonmark, Markdown 的严格规范。然而,由于 Commonmark 从未得到过 Markdown 创始人的加持,有人质疑它是否可以被认为是 Markdown。此外,在某些地方,规范自己承认直接违反了原始规则。无论如何,要成为 Commonmark 的实现,必须提供一个完整的解决方案,其中包含规范的所有记录特性。参考实现(在 JS 和 C 中)都非常大。实际上,我怀疑您是否可以像使用基于 rexed 的简单替换的实现来实现 Commonmark markdown.pl
。
关键是,除了最简单的实现之外,您得到的不仅仅是正则表达式替换的集合。确切的功能因实现而异,需要仔细阅读每个功能的文档。无论如何,即使是“简单”的正则表达式替换集合也相当复杂和冗长,要实现 Markdown 的所有记录功能。任何更少的东西都不会被视为 Markdown。
另一个考虑因素是性能。虽然基于正则表达式的解析器对于大多数一般用途来说“足够好”(作为参考实现的设计目的从命令行运行),但性能更高的实现(例如标记或 Commonmark 参考实现)会产生 AST 并使用渲染器. 基于正则表达式的实现永远不会在性能上接近匹配,如果您的 Web 服务器在每个请求上将 Markdown 转换为 HTML,这一点很重要。