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

时间:2013-12-24 21:43:03

标签: regex dfa nfa

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

[A-Z]
[^_]
.

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

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

我在询问NFA,但后来我想将NFA转换为DFA。

1 个答案:

答案 0 :(得分:4)

最简单的方法是:

  1. 使用细分作为NFA和DFA中转换的标签。例如,范围[a-z]将被重新表示为段[97, 122];单个字符' a'会成为[97,97];和任何角色'。'将成为[minCode, maxCode]

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

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

  4. 这对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步。要从&#34;设置状态&#34;创建新的转换。算法应修改如下:

       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时加快匹配,每个状态的转换可能按段进行排序并应用二进制搜索。

相关问题