实现一个 DFA 正则表达式引擎 - 3. NFA 的确定化
2015-05-17 11:18
337 查看
(正则引擎已完成,Github)
我们上一节已经将 NFA 构建出来了,我们的 NFAState 对象的结构实际上是这样的:
其中 transitionMap 是该状态接受 Character 后可以转换的状态的映射表。
那么以初始状态 0 为例,我们是不是可以认为状态 0 接受字符 a 后能去的状态全部包含在 transitionMap.get('a') 里面了呢?答案是否定的,因为我们需要考虑状态的闭包。正确答案应该是:
某状态 S 接受字符 c 可以转换到的状态集合为 S 的闭包接受字符 c 转换的状态集合的闭包。
通过这一条规则我们可以对 NFA 进行处理,构造一个考虑过闭包的 transitionMap:
之后就是对 NFA 的确定化。
确定化的思想即是把一个状态接受某字符所能到达的所有状态的集合作为一个状态,就是相当于并行地处理 NFA,原理部分没有找到非常通俗易懂的图,就先省略掉,可能以后会补上,大家可以参考编译原理或者自动机相关的书籍和网站。
到这里,我们就完成了 DFA 正则引擎的第三步:NFA 的确定化。
我们上一节已经将 NFA 构建出来了,我们的 NFAState 对象的结构实际上是这样的:
NFAState { private Set<NFAState> directTable; private Map<Character, Set<NFAState>> transitionMap; private int id; }
其中 transitionMap 是该状态接受 Character 后可以转换的状态的映射表。
那么以初始状态 0 为例,我们是不是可以认为状态 0 接受字符 a 后能去的状态全部包含在 transitionMap.get('a') 里面了呢?答案是否定的,因为我们需要考虑状态的闭包。正确答案应该是:
某状态 S 接受字符 c 可以转换到的状态集合为 S 的闭包接受字符 c 转换的状态集合的闭包。
通过这一条规则我们可以对 NFA 进行处理,构造一个考虑过闭包的 transitionMap:
Map<NFAState, Set<NFAState>> closureMap = calculateClosure(nfaStateList); // construct a NFA first Map<NFAState, Map<Character, Set<NFAState>>> nfaTransitionMap = new HashMap<>(); for (NFAState state : nfaStateList) { Map<Character, Set<NFAState>> subMap = new HashMap<>(); for (char ch = 0; ch < CommonSets.ENCODING_LENGTH; ch++) { Set<NFAState> closure = closureMap.get(state); Set<NFAState> reachable = traceReachable(closure, ch, closureMap); if (!reachable.isEmpty()) { subMap.put(ch, reachable); } } nfaTransitionMap.put(state, subMap); }
之后就是对 NFA 的确定化。
确定化的思想即是把一个状态接受某字符所能到达的所有状态的集合作为一个状态,就是相当于并行地处理 NFA,原理部分没有找到非常通俗易懂的图,就先省略掉,可能以后会补上,大家可以参考编译原理或者自动机相关的书籍和网站。
private void constructOriginalDFA(Set<NFAState> stateSet, Map<NFAState, Map<Character, Set<NFAState>>> nfaTransitionMap, Map<Set<NFAState>, Map<Character, Set<NFAState>>> originalDFATransitionMap) { Map<Character, Set<NFAState>> subMap = originalDFATransitionMap.get(stateSet); if (subMap == null) { subMap = new HashMap<>(); originalDFATransitionMap.put(stateSet, subMap); } for (char ch = 0; ch < CommonSets.ENCODING_LENGTH; ch++) { Set<NFAState> union = new HashSet<>(); for (NFAState state : stateSet) { Set<NFAState> nfaSet = nfaTransitionMap.get(state).get(ch); if (nfaSet != null) { union.addAll(nfaSet); } } if (!union.isEmpty()) { subMap.put(ch, union); if (!originalDFATransitionMap.containsKey(union)) { constructOriginalDFA(union, nfaTransitionMap, originalDFATransitionMap); } } } }
到这里,我们就完成了 DFA 正则引擎的第三步:NFA 的确定化。
相关文章推荐
- 实现一个 DFA 正则表达式引擎 - 2. NFA 的构建
- 实现一个 DFA 正则表达式引擎 - 4. DFA 的最小化
- 实现一个 DFA 正则表达式引擎 - 0. 要求
- 实现一个 DFA 正则表达式引擎 - 1. 语法树的构建
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
- 一个替换目录结构的正则表达式 实现目录的增加
- 简单正则表达式实现引擎
- 从0到1分步实现一个出生日期的正则表达式(JavaScript)
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——1 概述
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——3 计算4个函数
- 正则表达式引擎的构建——基于编译原理DFA(龙书第三章)——4 构造DFA
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。
- 用JavaScript的正则表达式验证网址格式是否正确,方法很多,这只是一个实现的方法.
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字
- 从0到1分步实现一个出生日期的正则表达式(JavaScript)
- 正则表达式原理及引擎简化递归实现
- 一个正则表达式引擎的设计和实施1-汤普森构造
- 简单功能的正则表达式引擎实现
- C实例---实现一个简单的正则表达式(删除重复的字符)