一.正则引擎的分类
1.正则引擎主要可以分为基本不同的两大类: DNF和NFA
同时可以粗略的分为三类: DFA(符合或不符合POSIX标准的都属此类)、传统型NFA、POSIX NFA.
2.部分程序使用的正则引擎类型
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: nawk、Mortice Kern Systems'utilities、GNU Emacs(明确指定时使用)
DFN/NFA混合: GNU awk、GNU grep/egrep、Tcl
3.测试引擎的类型
<1>查看是否是传统型NFA 测试忽略优先量词是否得到支持,如果是基本就能确实是传统型的NFA.因为DFA是不支持忽略优先量词的,在POSIX NFA中也没有意义. <2>DFA还是POSIX NFA DFA也不支持捕获型括号和回溯.也不支持环视和固化分组和条件判断和忽略优先.这一点有助于判断. 关于POSIX NFA看三者的总结篇.
二.匹配的基础 1.总结两条普适的原则
优先选择最最左端(最靠开头)的匹配结果.
标准的匹配量词(* ? +和{m,n})是匹配优先的.
2.匹配过程-----"失败"
匹配先从需要查找的字符串的起始位置尝试匹配.在这里,"尝试匹配"的意思是:在当前位置测试整个正则表达式能匹配的每样文本,如果在当前位置测试了所有的可能之后不能找到匹配结果,就需要从字符串的第二个字符之前的位置开始重新尝试.在找到匹配结果以前必须在所有位置重复此过程.只有在尝试过所有的起始位置(直到字符串的最后一个字符)都不能找到匹配结果的情况下,才会报告"匹配失败".
所以,如果要用正则表达式"ORA"来匹配"FLORAL",从字符串左边开始第一轮尝试会失败(因为"ORA"不能匹配FLO),第二轮尝试也会失败("ORA"同样不能匹配"LOR"),从第三个字符开始的尝试能够成功,所以引擎会停下来,报告匹配结果FL"ORA"L.
三.传动装置和驱动过程
1.传动装置的主要功能:----驱动
如果引擎不能再字符串开始的位置找到匹配的结果,传动装置就会推动引擎,从字符串的下一个位置开始尝试,然后是下一个,再下一个,如此继续.不过,如果某个正则表达式是以"字符串起始位置锚点"开始的,传动装置就会知道,不需要更多的尝试,因为如果能够匹配,结果肯定是从字符串的头部开始的.
2.引擎的构造
<1>文字文本: 如a、*、!、枝... 对于非元字符的文字字符,尝试匹配时需要考虑的就是"这个字符与当前尝试的字符是否相同".如果一个正则表达式只包含纯文本字符,如:"usa",那么正则引擎会将其视为:一个"u",接着一个"s",接着一个"a".
<2>字符组、点号、Unicode属性及其它 通常这一节的匹配是比较简单的:不论字符组的长度是多少,它都只能匹配一个字符.点号几乎能匹配任何字符.
<3>捕获型括号 用于捕获文本的括号(而并非用于分组)不会影响匹配的过程.
<4>锚点--eg:^ \z (?<=\d)... 锚点可以分为两大类:简单锚点(^ $ \G \b...)和复杂锚点(环视).
<5>非"电动"括号、反向引用和忽略优先量词 只有NFA引擎支持这些特性,而DFA引擎不支持.
四.标准量词是匹配优先的
标准匹配量词的结果"可能"并非所有可能中最长的,但是它们总是尝试匹配尽可能多的字符,直到匹配上限为止.如果匹配结果并非该表达式的所有可能中最长的,原因肯定是匹配字符过多导致匹配失败.
例如: 用"\b\w+s\b"来匹配包含"s"的字符串"regexes","\w+"完全能够匹配整个单词,但如果用\w+来匹配整个单词,"s"就无法匹配了.为了完成匹配,"\w+"必须只能匹配"regexe",把最后的"s\b"释放(交还)出来.或者说"s"强迫"\w+"将"s\b"释放出来.
如果表达式的其它部分能够匹配的唯一条件是:匹配优先的结构不匹配任何字符,在容许零匹配(如* ?等)的情况下是没问题的.不过,这种情况只有在表达式的后续部分强迫下才能发生.匹配优先量词之所以得名,是因为它们总是(或者,至少是尝试)匹配多于匹配成功下限的字符.
1.过度的匹配优先
"^.*([0-9][0-9])"或许是一个有用的正则表达式,它能够匹配一行字符的最后两位数字,如果有的话,将他们存储到"$1"中.
下面是匹配过程: "."首先匹配整行,而"[0-9][0-9]"是必须匹配的,在尝试匹配行末的时候会失败,这样它会通知".":"你占用的太多了,交出一些字符来吧,这样或许我能匹配".匹配优先组件首先会匹配尽可能多的字符,但为了整个表达式的匹配,它们通常需要"释放"一些字符(克制本能).当然,它们并不"愿意"这样做,只是不得已而为之.当然,"交还"绝不能破坏匹配的成立的必须条件,比如"+"的第一次匹配.
分析正则表达式"^.*([0-9][0-9])"匹配字符串"about 24 characters long"的过程:
".*"匹配整个字符串以后,第一个"[0-9]"的匹配要求".*"释放一个字符"g"(最后一个字符).但是这并不能让"[0-9]"匹配,所以".*"必须继续"交还字符",接下来"交还"的是"n'.如果循环15次,直到".*"最终释放"4"为止.
此时,即使第一个"[0-9]"能够匹配"4",第二个"[0-9]"仍然不能匹配.为了匹配整个正则表达式,".*"必须再次释放一个字符,这次是"2",由第一个"[0-9]"匹配.现在"4"能够由第二个"[0-9]"匹配,所以整个正则表达式匹配的结果是"about 24","$1"的值是"24".
2.匹配优先---先来先服务
多个匹配优先组件组成的正则表达式中,匹配的原则是---"先来先服务(或者理解为'先到先得')"---只要能保证整个正则的匹配成功(如果能)即可.
例如: 正则表达式"^.*[0-9]+"来匹配字符串"copyright 2003.".其中,"[0-9]+"匹配的结果是什么?答案是"3".匹配过程同上,其它自己想.
来源:oschina
链接:https://my.oschina.net/u/2882233/blog/758774