zoukankan      html  css  js  c++  java
  • 简易正则表达式引擎的实现

      正则表达式基本每个程序员都会用到,实现正则表达式引擎却似乎是一个很难的任务。实际上,掌握《编译原理》前端的词法分析部分知识就能够实现一个简单的正则表达式引擎。这里推荐一下网易云课堂的课程。http://mooc.study.163.com/course/USTC-1000002001?tid=1000003000#/info

    基本的正则表达式  正则表达式由字符与元字符组成,整个表达式用于描述符合某些特定特征的一类字符串,比如说表达式:abc,它表示 "abc" 这个字符串,由 'a', 'b', 'c' 三个字符按顺序连接在一起。本文要实现的正则表达式比较简单,只实现连接、选择、闭包的功能。定义直接从ppt里截图:

    实现的大概步骤如下:

    NFA指的是非确定自动机,对任意的字符,有多个状态可以转换。DFA指的是确定自动机,对任意的字符,最多只有一个状态可以转换。

    Thompson算法是一个递归算法,先将单个字符转换为nfa,再根据规则将nfa组合起来。单个字符(比如c)的转化如下

    两个字符(比如e1e2)则中间用ε连接

    接下来是选择(比如e1|e2)

    闭包(比如e1*)比较复杂

    知道了如何将小的nfa组合成大的nfa,那怎么处理正则表达式,将其转换为nfa呢?我们可以像处理四则运算那样,用两个栈来解决,但这只能应对简单情况。还可以用递归下降分析构建抽象语法树,a|b的语法树如下,递归下降分析的具体做法可以看前面推荐的视频或直接看源码

    由于nfa对任意的字符,有多个状态可以转换,我们需要将其转换为dfa。我们的nfa实际上是ε-NFA,有很多ε边,而dfa是没有ε边的,所以我们可以通过子集构造算法去除这些ε边。子集构造算法的大概思路是将从状态A出发接收某个字符能到达的所有状态(包括接收字符后再通过ε边到达)构成一个子集,这个子集所能到达的所有状态又构成一个子集,到最后就能消除ε边,得到dfa。

    对于下图的nfa

    子集构造算法步骤如下

    第一列第一行I的意思是从NFA的起始节点经过任意个ε所能到达的结点集合。Ia表示从该集合开始接收一个a所能到达的集合,Ib也就是接收一个b所能到达的状态的集合。

    如果Ia和Ib还没出现在I,就把它们填在接下的I里。结果如下

    得到dfa后再用Hopcroft算法最小化dfa,这个算法的思想是将等价的状态浓缩为一个结点。比如对于以下dfa

    可以简化为

    这样我们就完成了整个步骤,对于输入的字符串,如果能沿着dfa走到接收状态,就说明能够匹配。具体源码看这里 可能有bug,最后的最小化dfa也没有实现,轻喷。

    最后推荐几个相关链接

    轮子哥的教程 http://www.cppblog.com/vczh/archive/2008/05/22/50763.html

    http://www.cnblogs.com/cute/p/4021689.html 这个人写得比较清楚

    再推荐一下网易公开课的课程 http://mooc.study.163.com/learn/USTC-1000002001?tid=1000003000#/learn/content

  • 相关阅读:
    C# 图解教程 第一章 C#和.NET框架
    How I explained OOD to my wife(转)
    ListView 无 DataSource 依然用 DataPager 翻页
    【树莓派】crontab的两个问题
    【CentOS 7】scp示例
    【CentOS 7】nginx配置web服务器
    【CentOS_7】安装nginx
    【python 2.7】获取外部参数
    【python 2.7】输入任意字母数字,输出其对应的莫尔斯码并播放声音
    【python 2.7】python读取json数据存入MySQL
  • 原文地址:https://www.cnblogs.com/tonychen-tobeTopCoder/p/5211600.html
Copyright © 2011-2022 走看看