使用简单的基于正则表达式的降价解析器有什么缺点?

What are the downsides of using a simple regex-based markdown parser?

我的应用程序需要一个相对简单的降价解析器。只是一些简单的东西,比如粗体、斜体等等。我在四处寻找图书馆,很多图书馆似乎都很大。例如,marked is quite popular with 20,000 stars. And it's close to 2,000 lines of code. I'm not even sure how large this one是,但看起来相当复杂。

一般来说,我尽量保持简单并尽可能限制我的依赖性。我不确定所有这些线路在做什么?我很高兴很快发现 this library 甚至不到 100 行,它只是使用一个简单的正则表达式将文本转换为相应的降价。

我的问题基本上是其他图书馆在做什么?我是否通过选择使用更简单、以正则表达式为中心的方法而遗漏了什么?后一个库在某种程度上不安全吗?我是否应该考虑其他一些我不知道的因素?

显然我好像漏掉了一些重要的东西,因为前者的图书馆似乎很受欢迎,而后者连一颗星都没有。我只是不确定那是什么。我希望情况是后者适用于简单的情况,而前者更多 "complete" 如果那是你需要的,但我不想跳到那个结论。

有许多因素会导致 Markdown 解析器的复杂性。也就是说,您可以使用 "simple regex-based" 方法来构建 Markdown 解析器。其实这正是reference implementation uses (in Perl). It runs a series of regular expressions which replace the Markdown syntax with HTML syntax on the existing document. Even then, the source code is comprised of 1451 lines of code, including comments, license, etc. Of course, it includes support for the entire list of features described in the original syntax rules。这些功能包括对嵌套、转义等的支持,这使正则表达式的使用变得非常复杂。

有些人发现这样的实现存在局限性。这完全取决于您想要从 Markdown 解析器中得到什么。

例如,使用参考实现扩展语法几乎是不可能的。例如,Python-Markdown(我是其中的一名开发人员)采用了参考实现,为每个正则表达式命名,并为第三方扩展提供了一种方法来替换或插入新的正则表达式。样板代码只是为了允许添加更多的代码行。顺便说一下,Markdown 已经很老了,像 Python-Markdown 这样的库这些年来已经发生了变化和发展。第一个版本非常接近参考实现,但今天你很难看出它们之间有任何相似之处。

其他人对扩展语法不感兴趣,只是提供一种控制输出的方法。例如,marked JS library outputs an abstract syntax tree (AST), which can then be passed to a renderer. Renderers accept the AST (basically a list of tokens) and output some other format. That other format could be HTML, or it could be something else. Pandoc 就利用这一点在许多文档格式之间进行转换。当然,这会增加额外的代码行。

另一个因素,无论是否实施,许多人会争辩说,如果实施不支持规则中的所有功能,那么它就不是 Markdown。事实上,多年来,许多实现都添加了非标准功能(参见 GitHub Flavored Markdown 作为示例)。人们开始依赖这些非标准特性,并会提交错误报告,抱怨某个实现不支持它们。作为 Python-Markdown 的开发者,当 lib 实际上提供支持时,我经常看到这样的报告。它只是默认情况下未启用。当向他们指出这一点时,他们的反应往往不那么理解。因此,如果不支持所有标准功能,任何针对一般消费的实现都不会持续很长时间。

更复杂的是,在标准功能方面,实现之间并不完全一致。看到 Babelmark 2 FAQ for details. In that FAQ you will find a lot of documented differences which are rather nuanced. People really find these minor differences important. For that reason, a group of people created Commonmark, a strict specification for Markdown. However, as Commonmark has never received the blessing of the creator of Markdown, some question whether it can be considered Markdown at all. Additionally, in some places the spec, by its own admition, is in direct violation of the original rules. Regardless, for an implementation to be a Commonmark implementation is must provide a complete solution with all of the documented features of the spec. The reference implementations (在 JS 和 C 中)都相当大。事实上,我怀疑您是否可以使用像 markdown.pl 那样使用基于 rexed 的简单替换的实现来实现 Commonmark。

关键是,除了最简单的实现之外,您得到的不仅仅是一组正则表达式替换。确切的特性因实现而异,需要仔细阅读每个特性的文档。无论如何,即使 "simple" 正则表达式替换的集合也相当复杂且冗长,无法实现 Markdown 的所有文档化功能。低于此标准的将不被视为 Markdown。

另一个考虑因素是性能。虽然基于正则表达式的解析器 'good enough' 用于大多数一般用途(运行 从命令行作为参考实现的设计),但性能更高的实现(例如标记或 Commonmark 参考实现)产生AST 并使用渲染器。基于正则表达式的实现在性能上永远无法与它相提并论,如果您的 Web 服务器在每次请求时将 Markdown 转换为 HTML,这一点很重要。