如何使用字符范围实现正则表达式 NFA?

Posted

技术标签:

【中文标题】如何使用字符范围实现正则表达式 NFA?【英文标题】:How to implement regular expression NFA with character ranges? 【发布时间】:2014-01-13 01:25:48 【问题描述】:

当您阅读诸如Regex: NFA and Thompson's algorithm 之类的帖子时,一切看起来都相当简单,直到您意识到在现实生活中您不仅需要像“7”或“b”这样的直接字符,而且还需要:

[A-Z]
[^_]
.

即字符类(或范围)。因此我的问题是——如何使用字符范围构建 NFA?使用诸如“不是 A”、“其他任何东西”之类的元字符,然后计算重叠范围?这将导致在使用最终自动机时使用树状结构,而不仅仅是一个表格。

更新:请假设大小不小 (>>256) 字母。

我问的是 NFA,但后来我也想将 NFA 转换为 DFA。

【问题讨论】:

您能澄清一下“使用字符范围构建 NFA”的意思吗 @revo,用<a,k> 标记边缘,这意味着如果输入是j,则使用此标签,但如果输入是z,则不使用此标签。这并不难,但是有几个重叠的标签(<a,k>h<,>)可能会导致混乱。而且我不喜欢重新发明***,因此我在问。 关键在于你如何表现边缘。对于 8 位字符集,考虑 256 位的位图。例如,如果设置了位 n,则字符代码 n 在允许集中。 @tripleee,谢谢。我认为 8 位在实践中不会再飞了,Unicode 更有可能。但这意味着每个标签 8 KB (!)。这种方法是在任何公开的程序中使用的,还是只是理论上的想法? 如果您确实需要支持 Unicode,则需要考虑一系列其他注意事项。请参阅UTS-18 了解正则表达式支持。与此同时,也许只考虑以一种明智的方式支持 UTF-8 作为开始。 【参考方案1】:

最简单的方法是:

    在 NFA 和 DFA 中使用段作为转换的标签。例如,范围 [a-z] 将被表示为段 [97, 122];单个字符“a”将变为[97,97];和任何字符“。”会变成[minCode, maxCode]

    每个取反范围 [^a-z] 将导致从开始状态到下一个状态的两次转换。在此示例中,应创建两个转换 [minCode, 96][123, maxCode]

    当范围通过枚举所有可能的字符 [abcz] 来表示时,应该创建每个字符的转换,或者代码可能首先将字符分组到范围中以优化转换的数量。所以 [abcz] 会变成[a-c]|z。因此两个转换而不是四个。

这对于 NFA 来说应该足够了。但是,当字符范围相交时,将 NFA 转换为 DFA 的经典 power set construction 将不起作用。 要解决这个问题,只需要一个额外的泛化步骤。一旦创建了一组所有输入符号,在我们的例子中它将是一组线段,它应该被转换为一组不相交的线段。这可以在 O(n*Log(n)) 时间内完成,其中 n 是使用优先级队列 (PQ) 的集合中的段数,其中段按左组件排序。示例:

  Procedure DISJOIN:
   Input  <- [97, 99] [97, 100] [98, 108]
   Output -> [97, 97] [98, 99], [100, 100], [101, 108]

第 2 步。要从“设置状态”创建新的转换,应修改算法如下:

   for each symbol in DISJOIN(input symbols)
     S <- empty set of symbols
     T <- empty "set state"
     for each state in "set state"
      for each transition in state.transitions
        I <- intersection(symbol, transition.label) 
        if (I is not empty)
        
           Add I to the set S
           Add transition.To to the T
               

     for each segement from DISJOIN(S)
        Create transition from "set state" to T

为了在搜索转换和输入符号 C 时加快匹配速度,每个状态的转换可以按段排序并应用二分搜索。

【讨论】:

以上是关于如何使用字符范围实现正则表达式 NFA?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式构造相对应的ε-NFA

从正则表达式到 NFA 到 DFA 到最简 DFA

正则表达式: NFA引擎匹配原理

编译原理-第三章 词法分析-3.7 从正则表达式到自动机-从正则表达式构造NFA

自己动手写编译器:代码实现正则表达式到NFA状态机

自己动手写编译器:代码实现正则表达式到NFA状态机