使用基于 DFA(线性时间)的正则表达式捕获组:可能吗?

Posted

技术标签:

【中文标题】使用基于 DFA(线性时间)的正则表达式捕获组:可能吗?【英文标题】:Capture groups using DFA-based (linear-time) regular expressions: possible? 【发布时间】:2015-05-10 13:47:55 【问题描述】:

是否可以使用基于 DFA 的正则表达式实现捕获组,同时保持与输入长度相关的线性时间复杂度?

直觉上我认为不是,因为子集构建过程不知道它可能落在了哪个捕获组中,但这是我第一次意识到这可能是一个潜在的问题,所以我不知道。

【问题讨论】:

你的意思是仅仅捕获组,还是匹配反向引用? @Bergi:抓拍就行了。 【参考方案1】:

我的http://github.com/hoehrmann/demo-parselov 就是这样做的。我目前没有解释网页上的构造,但假设你有一个像

这样的语法
X = "a" B "c"
B = "b"

您可以将此常规语法转换为带有标记顶点的图

    开始 X “一个” 开始B “b” 最终B “c” 最终 X

DFA 状态对应于这些顶点的集合。第一个由顶点 1 和 2 组成,第二个由顶点 3 和 4 组成,然后是 5 和 6,最后是 7。如果您解析字符串“abc”,则有

    偏移量:0,顶点:[1, 2] 偏移量:1,顶点:[3, 4] 偏移量:2,顶点:[5, 6] 偏移量:EOF,顶点:[7]

这也是一个图表。您可以使用 (offset, vertex) 对作为顶点写出边:

    (o0, v1) -> (o0, v2) (o0, v2) -> (o1, v3) (o1, v3) -> (o1, v4) ...

这样的图可能包含最终不会到达最终顶点(EOF,v7)的顶点,但这样的顶点可以在 O(n) 时间内消除。如果语法不明确,则匹配将是通过结果图的路径。可能有很多可能的路径。

【讨论】:

【参考方案2】:

是否可以使用基于 DFA 的正则表达式实现捕获组,同时保持与输入长度相关的线性时间复杂度?

是的 - 至少在捕获组是确定性的情况下。考虑示例正则表达式/a|(a)/;将其与输入 "a" 匹配可以生成捕获的组,也可以不生成。

我认为捕获组可以基于使用finite state transducers 的理论基础,它类似于自动机,但也可以在更改状态时输出字符串。您可以回显输入,但例如用括号括住每个捕获组。

直觉上我认为不是,因为子集构建过程不知道它可能落在了哪个捕获组中,但这是我第一次意识到这可能是一个潜在的问题,所以我不知道。

确实,这是个问题。我认为您可以通过使用捕获状态标记您的集合来解决它,并同样区分结果 DFA 的状态。您可能无法为上述正则表达式生成完全确定性自动机,因为Wikipedia writes:“一些非确定性转换器不承认等效的确定性转换器”。

但是,子集构造过程的修改是可能的,请参阅Determinization of Transducers。他们的算法似乎围绕以下内容:

局部歧义 […] 通过尽可能延迟输出来解决,直到可以确定地写出这些符号。

例如,正则表达式/ab|(a)c/ 甚至/(a[bc])|ad/ 都可以解析为确定性转换器。请注意,它们的内存表示可能比没有捕获组时大得多。

【讨论】:

我试图了解确定性是否足够。是否可以为x*(a*b)c|x*(a?)(a?)bd 之类的模式制作 DFA?如果您延迟捕获直到看到cd,那么您已经解决了歧义问题,但是您如何知道应该在哪里开始和结束捕获呢?有没有办法在相对于输入长度的恒定时间(希望是恒定空间)内做到这一点?也许使用堆栈或其他东西? 嗯,好问题。我还没有深入研究有限状态传感器。我认为您可以通过按后缀区分捕获组来解决这个问题,即abc 上的/x*(a*b)c|x*(a*b)d/ 应该输出(ab0)cxabd 上应该输出x(ab1)d。这些换能器可以确定为相当简单的形式。请注意,您将始终需要输入长度的线性时间;输出(空间)也将是线性的,但如果您优化并使用指向输入的指针,您应该得到线性空间 wrt 捕获组的数量。 我明白了。请注意,恒定时间是指每个状态转换时的输入长度恒定(因为有 n 个状态转换)。关于捕获,这是用户指定的内容,所以如果我可以更改它们并稍后快速恢复用户想要的内容。 对 - 但由于输出需要线性时间,我猜状态转换所花费的时间摊销为常数。

以上是关于使用基于 DFA(线性时间)的正则表达式捕获组:可能吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥正则表达式可选非捕获组不作为可选并且搞砸匹配?

基于 DFA 的正则表达式匹配 - 如何获取所有匹配项?

c# 正则表达式捕获

如何使用 DFA 正则表达式匹配器实现正则表达式断言/环视(即 \b 样式字边界)

正则表达式的$

从正则表达式到 NFA 到 DFA 到最简 DFA (结束)