最简单的方法是:
在 NFA 和 DFA 中使用段作为转换的标签。例如, range [az] 将被表示为 segment [97, 122]
;单个字符 'a' 将变为[97,97]
; 和任何字符“。” 会变成[minCode, maxCode]
.
每个否定范围 [^az] 将导致从开始状态到下一个状态的两次转换。在此示例中,应创建两个转换[minCode, 96]
和。[123, maxCode]
当通过枚举所有可能的字符 [abcz] 来表示范围时,应该创建每个字符的转换,或者代码可能首先将字符分组到范围中以优化转换的数量。所以 [abcz] 会变成[a-c]|z
. 因此,两个转换而不是四个。
这对于 NFA 来说应该足够了。然而,当字符范围相交时,将 NFA 转换为 DFA 的经典幂集构造将不起作用。要解决这个问题,只需要一个额外的泛化步骤。一旦创建了一组所有输入符号,在我们的例子中它将是一组线段,它应该被转换为一组不相交的线段。这可以在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 时加快匹配速度,每个状态的转换可以按段排序并应用二进制搜索。