我有一个随机排列的正则表达式数组,如下所示:
let patterns = [
/foo+ba+r/,
/foo/,
/foo+bar/,
/foobar/,
/m[eo]{4,}w/,
/boo/,
/fooo*/,
/meow/
]
我不确定这是否可行,但我想写一个算法,将正则表达式从最不贪婪到最贪婪排序,如下所示:
[
/foo/,
/boo/,
/fooo*/,
/meow/,
/foobar/,
/foo+bar/,
/m[eo]{4,}w/,
/foo+ba+r/
]
我可以想象这样的排序可以这样实现:
patterns.sort((p1, p2) { return p1.greediness() - p2.greediness() });
但是在RegExpr
类中不存在名为greediness
的方法。
理想情况下,greediness
方法将返回最少可能匹配的字符数,即:
/foo/.greediness() == 3
/boo/.greediness() == 3
/fooo*/.greediness() == 3
/meow/.greediness() == 4
/foobar/.greediness() == 6
/foo+bar/.greediness() == 6
/m[eo]{4,}w/.greediness() == 6
/foo+ba+r/.greediness() == 6
你对这个问题的解决方案是什么?
2条答案
按热度按时间u5rb5r591#
这确实是一个非常困难的问题,它需要解析正则表达式的能力(如果正则表达式的规则被简化,只允许输入"正则"字符和特殊的regex特殊字符
()[]|*+?
,那么构造这样一个解析器就不会太困难了)。1.将正则表达式转换为非确定性有限自动机(NFA)。这一步需要一个好的正则表达式解析器,但一旦你有了它,NFA的构造就很简单了。当然,如果你能找到一个现成的正则表达式来实现NFA,那就太理想了。
1.构造NFA的有向加权图表示,对表示字符转换的边赋予权重1,对表示ε转换的边赋予权重0。
1.使用Dijkstra算法找到从NFA的初始状态到最终状态的最短路径。
让我们以正则表达式
m[eo]{2,}w
为例,将其转换为一个NFA,并在适当的边上标记权重,在边下标记导致状态转换的字符,我们得到:如果一条边由
[from-state, to-state, weight]
组成的元素的长度为3的数组定义,则上述有向图的边的数组将是:应用Dijkstra算法以获得从状态0到状态12的最短路径产生长度为4的以下路径:
0 -> 1 -> 3 -> 5 -> 6 -> 8 -> 10 -> 11 -> 12
因此正则表达式识别的最短字符串将是4。
因此,现在您需要做的就是找到或编写一个JavaScript正则表达式,用于NFA算法和Dijkstra算法。
如果你正在创建自己的正则表达式解析器,那么你实际上可以跳过创建NFA和Dijkstra算法,而是计算长度。下面的内容并不意味着是一个完整的解析器。例如,它不支持命名组,并且它只识别基本的"stuff"。
See Demo
图纸:
sg3maiej2#
正如Pointy在评论中所说,这是一个难题。
下面是解决方案的开始:
我们只需要将正则表达式的文本用可能匹配的最少字符数替换量词及其前面的字符,对于
[eo]
和X{4,}
这样的块,我们做了类似的操作。我们可能会经历这样的步骤:
但这并没有触及正则表达式内部的复杂性,甚至没有尝试处理捕获组。我认为这几乎不可能在完整的正则表达式规范中实现,但也许这可以扩展到您所需要的。
(If你会变得更复杂,你可能想用类似下面的代码重复做这个,或者用一个
while
循环代替它的递归。