这篇主要是基于《精通正则表达式》的一篇读书笔记,因为书还没看完,可能以后还会有相关的笔记。(工作以后看书的效率真的很低啊……)

正则引擎主要可以分为基本不同的两大类:一种是DFA(确定性有穷自动机,学过计算理论的应该都知道),另一种是NFA(非确定性有穷自动 机),DFA和NFA都有很长的历史,NFA的历史更长一些,两者在二十多年的发展中产生了许多不必要的变体。而POSIX标准的出台是为了规范这种现 象。POSIX标准不但清楚地规定了引擎应该支持的元字符和特性,还明确规定了使用者期望由表达式获得的准确结果。DFA已经符合新的标准,而NFA则需 要修改才能符标准。这样一来,正则引擎可以粗略地分为3类:DFA、传统型NFA、POSIX NFA,表格 1是从书中摘出来的,基本涵盖了现在主流的大部分程序。

引擎类型 程序
DFA awk (大多数版本)、egrep(大多数版本)、flex、lex、MySQL、Procmail
传统型NFA GNU Emacs、Java、grep(大多数版本)、less、more、.NET语言、PCRE library、Perl、PHP(所有三套正则库)、Python、Ruby、sed(大多数版本)、vi
POSIX NFA mawk、Mortice Kern Systems’ utilities、GNU Emacs (明确指定时使用)
DFA/NFA 混合 GNU awk、GNU grep/egrep、Tcl

表格1

DFA和NFA反映了将正则表达式在应用算法上的根本差异。NFA可以称为表达式主导的引擎,DFA则可以称为文本主导。所谓表达式主导是指在每一 个匹配过程中,每一个子表达式都是独立的,或者可以认为一条由多个子表达式组成的正则表达式在表达式主导的引擎中等效于基本等效于多条表达式串行执行(当 然公共部分是不会被重复执行的)。而在文本主导的引擎中,多条子表达式会在扫描文本时同时进行匹配。

在书上举了个例子,基本说明了这两种方式的不同:用to(nite|knight|night)匹配文本’tonight’,当表达式主导引擎来匹 配时,在匹配完to后会依次匹配nite、knight、night直到匹配成功为止(即匹配night时)。而文本主导的引擎匹配时,会记录当前有效的 所有匹配可能,所以当匹配完to时,由于knight的k不能匹配,所以被淘汰出局,这时剩下的是两个有效的可能匹配(nite和night),当扫描到 g时就只剩下一个可能匹配了,当h和t完成匹配时,引擎发现匹配完成,报告成功。

以上的匹配过程其实引出了几个概念,同时我们也可以从这个例子中看出两种引擎的不同。在NFA中由于表达式主导的串行匹配方式,所以用到了回溯 (backtracking),按照书中的说法,这个是NFA最重要的部分,每一次某个分支的匹配失败都会导致一次回溯,因此如何正确的选择表达式,减少 回溯次数就成为了提高NFA引擎下正则表达式工作效率的关键。具体内容可以参考相关资料。另外还有两个DFA中没有的概念:“匹配优先量词”和“忽略优先 量词”。(在DFA中只有匹配优先,这个也很好理解,一方面是DFA没有也不需要回溯,另外一个原因是DFA的最左最长原则,在下文会提到)这里也不展开 了,网上有不少资料讲这两个概念,以及如何灵活选择两种量词来提高效率的范例。

总的来说DFA和NFA的明显区别之一在于效率,正如上面说到的,由于DFA没有回溯,因此看起来在某些情况下会比NFA来得更快,但是在真正使用 中,DFA需要进行预编译才能获得更好效果,因为DFA的匹配方式需要更多的内存和时间,在第一次遇到正则表达式时需要比NFA详细得多的方法来分析这个 表达式,不过可以预先把对不同正则表达式的分析结果建好,DFA就可以获得比NFA更优的速度。虽然NFA速度更慢,并且实现复杂,但是它又有着比DFA 强大的多的功能,比如支持环视,支持反向引用(虽然这个是非正则的)等。除此之外,最大的区别就在于最左最长规则(longest of the leftmost)这是在POSIX标准中规定的一条原则,即如果在字符串的某个位置存在多个可能的匹配,则返回的是最长的匹配,又由于匹配时总是从左边 开始的,所以叫最左最长规则。DFA天然地支持这一条规则,而NFA由于使用了回溯,并且会在匹配时立刻返回结果,再加上忽略优先量词的存在,使得它天然 地不支持这条规则……,当然如果对NFA进行一些修改,要求其在首次匹配时不是停下来而是穷尽所有结果,最后返回最长的结果,则NFA就被改造成了 POSIX NFA。

正则表达式的终极境界是兼具DFA的速度和NFA的功能,比如GNU grep采取了一种简单有效的策略,在平时尽可能多地使用DFA,在需要用到反向引用的时候,才切换到NFA,可以得到很不错的结果。

<转>(笔记)正则表达式的几种引擎的更多相关文章

  1. JAVA学习笔记--正则表达式

    正则表达式是一种强大而灵活的文本处理工具.使用正则表达式,可以让我们以编程的方式构造复杂的文本,并对输入的字符串进行搜索. 一.基础正则表达式语法(表格来自J2SE6_API) 字符 x 字符 x \ ...

  2. 小菜鸡的学习笔记---<正则表达式(1)>

    正则表达式学习笔记(1) (纯新手学习笔记,大佬绕路 QAQ) 一.简介 正则表达式就是一种文本模式用来匹配一系列满足特定条件的字符串,可以对比一下数学里面的表达式,比如我们要用一个表达式表示一串数字 ...

  3. JVM学习笔记:字节码执行引擎

    JVM学习笔记:字节码执行引擎 移步大神贴:http://rednaxelafx.iteye.com/blog/492667  

  4. Mysql表的七种引擎类型,InnoDB和MyISAM引擎对比区别总结

    InnoDB和MyISAM区别总结 我用MySQL的时候用的是Navicat for MySQL(Navicat for mysql v9.0.15注册码生成器)操作库.表操作的,默认的表就是Inno ...

  5. MySQL数据库的几种引擎

    有些东西其实一直在用,但是突然问起来它是啥,可能你会很陌生,很陌生,很陌生 ....... mysql的四种引擎: 1.MyISAM存储引擎 不支持事务,不支持外键,优势是访问速度快,对事务完整性没有 ...

  6. mongodb 系列 ~ mongo的两种引擎介绍对比

    一 简介 两种引擎方式的对比二  对比与说明   1 版本支持      MMAP引擎 3.2版本之前,默认引擎       WT 引擎 3.2版本之后,默认引擎   2 并发性能(核心)     M ...

  7. mysql中有多种存储引擎,每种引擎都有自己的特色

    mysql中有多种存储引擎,每种引擎都有自己的特色. 用途: MyISAM:快读, Memory:内存数据, InnoDB:完整的事务支持 锁: MyISAM:全表锁定, Memory:全表锁定, I ...

  8. 分享知识-快乐自己:mysql数据库常见两种引擎

    mysql的常用引擎 在MySQL数据库中,常用的引擎主要就是2个:Innodb和MyIASM. 首先: 1.简单介绍这两种引擎,以及该如何去选择. 2.这两种引擎所使用的数据结构是什么. Innod ...

  9. mongodb3.0版本的2种引擎对比

    mongodb3.0以后 增加了wiredtiger引擎.常规引擎也升级到MMAPv1引擎(MongoDB2.6及以下版本用的是MMAP引擎):   mmapv1引擎:             col ...

随机推荐

  1. JDBC连接MySql,配置url报错

    使用JDBC连接MySql时出现:The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one ...

  2. mac安装oh my zsh

    克隆项目到本地 git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh 2.创建配置文件 cp ~/.oh-my-zsh/ ...

  3. 13个开源GIS软件 你了解几个?

    地理信息系统(Geographic Information System,GIS)软件依赖于覆盖整个地球的数据集.为处理大量的 GIS 数据及其格式,编程人员创建了若干开源库和 GIS 套件. GIS ...

  4. 58.UIScrollView XIB拖拽约束

    第一步: 拖拽UIScrollView 到控制器上 ,给scrollView 添加约束 ,这时是正常的 第二步:scrollview上添加UIview ,(注意:这个 ScrollView就是根据这个 ...

  5. flask框架基础

    一 web的一些框架介绍 Flask:短小精悍,内部没有包含多少组件,但是第三方的组件是非常丰富的. Django:django是一个重武器,内部包含了非常多的组件:orm,form,modelFor ...

  6. Python10/22--面向对象编程/类与对象/init函数

    类: 语法: class关键字 类名# 类名规范 大写开头 驼峰命名法class SHOldboyStudent: # 描述该类对象的特征 school = "上海Oldboy" ...

  7. PHP中require(),include(),require_once()和include_once()有什么区别

    引用文件的方法有两种:require 及 include.两种方式提供不同的使用弹性. require 的使用方法如 require("MyRequireFile.php"); . ...

  8. JS页面跳转大全

    所谓的js页面跳转就是利用javesrcipt对打开的页面ULR进行跳转,如我们打开的是A页面,通过javsrcipt脚本就会跳转到B页面.目前很多垃圾站经常用js跳转将正常页面跳转到广告页面,当然也 ...

  9. 2019.01.26 codeforces 528D. Fuzzy Search(fft)

    传送门 fftfftfft好题. 题意简述:给两个字符串s,ts,ts,t,问ttt在sss中出现了几次,字符串只由A,T,C,GA,T,C,GA,T,C,G构成. 两个字符匹配的定义: 当si−k, ...

  10. c#在panel或groupbox中添加窗体,实现点击不同按钮或combox时panel中窗体切换,在xtratabcontrol中添加窗体

    参考panel添加窗体: http://blog.csdn.net/illegalname/article/details/65444249 http://blog.csdn.net/Eastmoun ...