【发布时间】:2019-05-16 22:24:50
【问题描述】:
对于 Google Prettify 语法高亮器 for the Wolfram Language,我需要将所有标识符与大约 7000 个内置函数名称的大列表进行匹配,以将它们作为关键字高亮显示。过去,我只是使用由many alternations 组成的正则表达式。举个具体的例子,下面是所有以Plot开头的函数:
(:?Plot|Plot3D|Plot3Matrix|PlotDivision|PlotJoined|PlotLabel|PlotLabels|PlotLayout|PlotLegends|PlotMarkers|PlotPoints|PlotRange|PlotRangeClipping|PlotRangeClipPlanesStyle|PlotRangePadding|PlotRegion|PlotStyle|PlotTheme)
理论上,这是一个糟糕的选择,因为需要对每个备选关键字重复进行子匹配。可以做的是构建一个Trie (or prefix tree) 并从中构建一个正则表达式。如果前缀不正确,这将跳过整个所有子匹配。对于上面的话,应该是这样的
(:?Plot(?:3(?:D|Matrix)|Division|Joined|L(?:a(?:bel(?:s)?|yout)|egends)|Markers|Points|R(?:ange(?:Clip(?:PlanesStyle|ping)|Padding)?|egion)|Style|Theme)?)
虽然这看起来有点乱,但想法很简单:它测试前缀Plot,如果不匹配,则不需要进一步测试。如果匹配,则跳转到内部表达式并测试下一个前缀,直到它完全匹配或不匹配。
我已经为所有 7000 个与自己匹配的关键字和 7000 个字典单词作为否定示例 with Kotlin 计时了正则表达式。 Trie 实现需要 78 毫秒,而交替正则表达式需要 523 毫秒。这是我预期的巨大改进。
但是,在 JavaScript 中,Trie 实现似乎有点慢。为了进行分析,我设置了 2 个网页,它们使用两种不同的方法调用美化引擎。 Here 是 Trie 实现,here 是替代实现。然后我使用 Chrome 开发工具对此进行了分析,但我对 JS 并不是特别有经验。
问题:
【问题讨论】:
-
我的直觉告诉我应该在codereview.stackexchange.com 上问这个问题(但是,在这种情况下可能行不通)。
-
RegExp 引擎通常将 regexp 解析为有限自动机。所以它与你天真的假设的方式不匹配。
-
解析的时候可以检测出常用前缀,并像Trie一样实现。
-
@Barmar 好的,所以一个假设是引擎在内部做了类似的事情并构建了一个使用公共前缀的自动机。这听起来很合理。我希望找到的是提到这一点的某种参考。我检查了许多 JS 正则表达式性能帖子,但确实找不到我想要的。
-
this 看起来是关于如何实现正则表达式的论文链接的一个很好的集合。
标签: javascript regex regex-lookarounds regex-group regex-greedy