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

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

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

【问题讨论】:

  • 你的意思是仅仅捕获组,还是匹配反向引用?
  • @Bergi:抓拍就行了。

标签: regex finite-automata dfa


【解决方案1】:

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

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

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

  1. 开始 X
  2. “一个”
  3. 开始B
  4. “b”
  5. 最终B
  6. “c”
  7. 最终 X

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

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

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

  1. (o0, v1) -> (o0, v2)
  2. (o0, v2) -> (o1, v3)
  3. (o1, v3) -> (o1, v4)
  4. ...

这样的图可能包含最终不会到达最终顶点(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 个状态转换)。关于捕获,这是用户指定的内容,所以如果我可以更改它们并稍后快速恢复用户想要的内容。
    • 对 - 但由于输出需要线性时间,我猜状态转换所花费的时间摊销为常数。
    猜你喜欢
    • 1970-01-01
    • 2021-08-11
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2022-11-21
    相关资源
    最近更新 更多