文章目录
- 前言
- 参考目录
- 学习笔记
- 1:正则表达式
- 1.1:表示
- 1.2:快捷表示
- 2:正则表达式与非确定有限状态自动机 REs and NFAs
- 2.1:二元性
- 2.2:模式匹配实现
- 2.3:非确定有限状态自动机 Nondeterministic finite-state automata
- 2.4:非确定性
- 3:NFA 模拟
- 3.1:demo 演示
- 3.2:Java 实现
- 3.3:分析
- 4:NFA 构造
- 4.1:构造与正则表达式对应的 NFA
- 4.2:实现
- 4.3:demo 演示
- 4.4:Java 实现
- 4.5:分析
- 5:非正则表达式
- 6:背景
- 7:小结
前言
本篇主要内容包括:正则表达式、非确定有限状态自动机 NFA。
建议在学习本篇之前先行学习或回顾上一篇子字符串查找的内容。
参考目录
- B站 普林斯顿大学《Algorithms》视频课
(请自行搜索。主要以该视频课顺序来进行笔记整理,课程讲述的教授本人是该书原版作者之一 Robert Sedgewick。) - 微信读书《算法(第4版)》
(本文主要内容来自《5.4 正则表达式》) - 官方网站
(有书本配套的内容以及代码)
学习笔记
注1:下面引用内容如无注明出处,均是书中摘录。
注2:所有 demo 演示均为视频 PPT demo 截图。
注3:如果 PPT 截图中没有翻译,会在下面进行汉化翻译,因为内容比较多,本文不再一一说明。
1:正则表达式
1.1:表示
对应书本章节:《5.4.1 使用正则表达式描述模式》
- 5.4.1.1 连接操作
- 5.4.1.2 或操作
- 5.4.1.3 闭包操作
- 5.4.1.4 括号
1.2:快捷表示
对应书本章节:《5.4.2 缩略写法》
- 5.4.2.1 字符集描述符
- 5.4.2.2 闭包的简写
- 5.4.2.3 转义序列
2:正则表达式与非确定有限状态自动机 REs and NFAs
2.1:二元性
RE(正则表达式): 简洁描述一组字符串的方法。
DFA(确定有限状态自动机): 一种机器,用于判断给定的字符串是否属于预定义的字符串集合。
克林宁定理(Kleene’s theorem):
- 对于任何确定有限状态自动机(DFA),都存在一个能够描述相同字符串集合的正则表达式(RE)。
- 对于任何正则表达式(RE),都存在一个能够识别相同字符串集合的确定有限状态自动机(DFA)。
2.2:模式匹配实现
类似于 KMP 算法:
- 不需要文本输入流回溯。
- 确保二次时间复杂度(通常为线性时间)。
基础抽象概念: 非确定有限状态自动机(NFA)。
基本策略:[应用克林宁定理]
- 从正则表达式构建 NFA。
- 使用文本作为输入模拟 NFA。
2.3:非确定有限状态自动机 Nondeterministic finite-state automata
对应书本章节:《5.4.4 非确定有限状态自动机》。
也有可能进入错误状态并停滞:
2.4:非确定性
Q. 如何确定一个字符串是否被自动机所匹配?
DFA(确定有限状态自动机): 判定较为简单,因为对于每个状态和输入字符,恰好有一个适用的转换。
NFA(非确定有限状态自动机): 可能存在多个适用的转换;需要正确选择其中一个!
Q. 如何模拟 NFA?
A. 系统地考虑所有可能的转换序列来进行模拟。
3:NFA 模拟
3.1:demo 演示
该 demo 建议多观看几遍视频理解操作步骤。
3.2:Java 实现
edu.princeton.cs.algs4.NFA
![![image-20240402164427969]](https://img-blog.csdnimg.cn/direct/425e2743ce4b4554941f78fd58a12e87.png)
edu.princeton.cs.algs4.NFA#NFA
/*** Initializes the NFA from the specified regular expression.** @param regexp the regular expression*/public NFA(String regexp) {this.regexp = regexp;m = regexp.length();Stack<Integer> ops = new Stack<Integer>();graph = new Digraph(m+1);for (int i = 0; i < m; i++) {int lp = i;if (regexp.charAt(i) == '(' || regexp.charAt(i) == '|')ops.push(i);else if (regexp.charAt(i) == ')') {int or = ops.pop();// 2-way or operatorif (regexp.charAt(or) == '|') {lp = ops.pop();graph.addEdge(lp, or+1);graph.addEdge(or, i);}else if (regexp.charAt(or) == '(')lp = or;else assert false;}// closure operator (uses 1-character lookahead)if (i < m-1 && regexp.charAt(i+1) == '*') {graph.addEdge(lp, i+1);graph.addEdge(i+1, lp);}if (regexp.charAt(i) == '(' || regexp.charAt(i) == '*' || regexp.charAt(i) == ')')graph.addEdge(i, i+1);}if (ops.size() != 0)throw new IllegalArgumentException("Invalid regular expression");}
edu.princeton.cs.algs4.NFA#recognizes
/*** Returns true if the text is matched by the regular expression.** @param txt the text* @return {@code true} if the text is matched by the regular expression,* {@code false} otherwise*/public boolean recognizes(String txt) {DirectedDFS dfs = new DirectedDFS(graph, 0);Bag<Integer> pc = new Bag<Integer>();for (int v = 0; v < graph.V(); v++)if (dfs.marked(v)) pc.add(v);// Compute possible NFA states for txt[i+1]for (int i = 0; i < txt.length(); i++) {if (txt.charAt(i) == '*' || txt.charAt(i) == '|' || txt.charAt(i) == '(' || txt.charAt(i) == ')')throw new IllegalArgumentException("text contains the metacharacter '" + txt.charAt(i) + "'");Bag<Integer> match = new Bag<Integer>();for (int v : pc) {if (v == m) continue;if ((regexp.charAt(v) == txt.charAt(i)) || regexp.charAt(v) == '.')match.add(v+1);}if (match.isEmpty()) continue;dfs = new DirectedDFS(graph, match);pc = new Bag<Integer>();for (int v = 0; v < graph.V(); v++)if (dfs.marked(v)) pc.add(v);// optimization if no states reachableif (pc.size() == 0) return false;}// check for accept statefor (int v : pc)if (v == m) return true;return false;}
3.3:分析
对应书本命题 Q:
4:NFA 构造
4.1:构造与正则表达式对应的 NFA
状态: 为正规表达式(RE)中的每个符号创建一个状态,同时添加一个接受状态。
连接操作: 从字母表中字符对应的当前状态添加匹配转换边至下一个状态。
括号: 从括号所在的状态添加一条 ε - 转换边至下一个状态。
闭包操作: 对于每一个运算符,添加三条 ε - 转换边。
或表达式: 对于每一个 |(逻辑或)操作符,添加两条 ε - 转换边。
4.2:实现
目标: 编写一个程序来构建 ε - 转换有向图。
挑战: 记忆左括号以实现闭包和逻辑或;记忆逻辑或符号 | 以实现逻辑或操作。
解决方案: 维护一个栈结构。
- 遇到
(符号时:将(入栈。 - 遇到
|符号时:将|入栈。 - 遇到
)符号时:弹出与之配对的(及其间的所有|符号;然后根据闭包和逻辑或的规则,添加相应的 ε - 转换边。
4.3:demo 演示
4.4:Java 实现
4.5:分析
对应书本命题 R:
5:非正则表达式
反向引用:
\1表示法用于匹配先前已匹配到的子表达式。- 这一特性在典型的正则表达式实现中得到支持。
某些非正则表达式的例子:
- 形如 ww 的字符串,其中 w 是任意字符串,例如
beriberi。 - 包含复合数量 1 的单字符字符串,例如
111111。 - 含有相同数量 0 和 1 的二进制字符串,例如
01110100。 - Watson-Crick 互补的回文串,例如
atttcggaaat。
注解: 使用反向引用进行模式匹配的问题属于难解问题(不可行或计算复杂度较高)。
6:背景
抽象机、语言及非确定性概念:
- 是计算理论的基础。
- 自20世纪30年代以来就被深入研究。
- 是现代编程语言的基础。
编译器:
- 编译器是一种程序,负责将源程序翻译成机器码。
- KMP 算法处理的字符串模式可以转换为确定有限自动机(DFA)。
- grep 工具使用的正则表达式可以转换为非确定有限自动机(NFA)。
- javac 编译器将 Java 语言源代码编译为 Java 字节码。
7:小结
程序员:
- 通过 DFA 模拟实现子串搜索功能。
- 通过 NFA 模拟实现正则表达式模式匹配。
理论学者:
- 正则表达式是描述一组字符串的紧凑表示方法。
- NFA 是非确定性抽象机,其功能等价于正则表达式。
- DFA、NFA 以及正则表达式都有其局限性。
你: 实际应用计算机科学的核心原理。
举例说明计算机科学中的关键范例:
- 构建中间抽象层。
- 挑选恰当的抽象模型!
- 解决重要的实际问题。
(完)
![![L20-54RegularExpressions_06]](https://img-blog.csdnimg.cn/direct/45051ac742094ca88a190f256b010c94.png)
![![L20-54RegularExpressions_07]](https://img-blog.csdnimg.cn/direct/1e46a46c1e23406db7de86781e6cb391.png)
![![L20-54RegularExpressions_16]](https://img-blog.csdnimg.cn/direct/1a7c2df698ad45ce8687610ea286b425.png)
![![L20-54RegularExpressions_18]](https://img-blog.csdnimg.cn/direct/6fb36840e41f43ee98e065bd94907769.png)
![![image-20240402093803403]](https://img-blog.csdnimg.cn/direct/3ca4f48548fe4e6ab2a0a9909d0579e3.png)
![![image-20240402094701193]](https://img-blog.csdnimg.cn/direct/7394f8c0f16a4ba3adcbae0bf60798af.png)
![![image-20240402095141143]](https://img-blog.csdnimg.cn/direct/a2798c86205241c3af9947033777d794.png)
![![image-20240402095201507]](https://img-blog.csdnimg.cn/direct/93c3ebba3db64dcaa7d1b8d6afada77a.png)
![![L20-54RegularExpressions_23]](https://img-blog.csdnimg.cn/direct/5a8e26373f54459f84200b70d3840e03.png)
![![image-20240402163328370]](https://img-blog.csdnimg.cn/direct/8b2c9fae61bb40a38a7076947dc568ab.png)
![![image-20240402163446270]](https://img-blog.csdnimg.cn/direct/1bcda96993e946338f99513fcd7b6a69.png)
![![L20-54RegularExpressions_32]](https://img-blog.csdnimg.cn/direct/e778ba7dbbb84a36a87be0e4ecf5c317.png)
![![image-20240402164943402]](https://img-blog.csdnimg.cn/direct/c9ef12321661432aa292870201e52727.png)
![![L20-54RegularExpressions_34]](https://img-blog.csdnimg.cn/direct/a5a277920be04e3599c69181a2833a37.png)
![![L20-54RegularExpressions_35]](https://img-blog.csdnimg.cn/direct/9be85b8a8aaa471994cc201f64d3f70d.png)
![![L20-54RegularExpressions_36]](https://img-blog.csdnimg.cn/direct/f667dcbc948f4eb8b529483743f207e8.png)
![![L20-54RegularExpressions_37]](https://img-blog.csdnimg.cn/direct/33e194881fa14e548f9e588cc4a38e31.png)
![![L20-54RegularExpressions_38]](https://img-blog.csdnimg.cn/direct/c74188d8f27040d19160bd12b99c99a8.png)
![![L20-54RegularExpressions_39]](https://img-blog.csdnimg.cn/direct/6b3e323b5bc34d13bc9655fa908a80ad.png)
![![image-20240402173630494]](https://img-blog.csdnimg.cn/direct/c532fc04dab446ae8907eb9fb648a7c9.png)
![![L20-54RegularExpressions_42]](https://img-blog.csdnimg.cn/direct/b33d4a8783a348f281c3f2c6e179aeee.png)
![![L20-54RegularExpressions_43]](https://img-blog.csdnimg.cn/direct/ea1b333245d5435b9724414899bb2552.png)
![![image-20240402174323446]](https://img-blog.csdnimg.cn/direct/c94bef0764a24bc885e1fca323da3c6e.png)
![![L20-54RegularExpressions_53]](https://img-blog.csdnimg.cn/direct/c098e43562ca46208c7ebaea0a7ee09d.png)
![![L20-54RegularExpressions_54]](https://img-blog.csdnimg.cn/direct/3c3c344b43e1480781c515ade76642fa.png)
![![L20-54RegularExpressions_55]](https://img-blog.csdnimg.cn/direct/920e7ed5df47400480fb9122a3cdecee.png)