表达式的匹配原理
一)正则引擎的分类
1.DFA(符合或者不符合POSIX标准的都属于此类):电动机
2.传统NFA: 传统的汽油机
3.POSIX NFA:符合新标准的汽油机
二)两条规则
规则1:优先选择最左端的匹配结果
匹配先从需要查找的字符串的起始位置尝试匹配,即从第一个字符开始测试整个正则表达式,如果测试了所有
可能后仍然找不到结果,则从第二个字符开始测试,直到找到结果。
例如:
1.用'ORA'来匹配FLOARAL,从字符串左边开始的第一轮匹配会失败(因为ORA不能匹配FLO),同理
第二轮也会失败,第三轮成功。
2.用'cat'来匹配:
The dragging belly indicates that your cat is too fat.
匹配结果是indicates中的cat
3.用'fat|cat|belly|your'匹配2中的句子,结果是?
注意:锚点直接匹配位置。
规则2: 标准量词是匹配优先的
标准匹配量词:?,*,+,{min, max}
如果用这些量词来约束某个表达式,例如'(tang)*'中的'tang', 'a?'中的'a',在匹配成功之前,进行尝试的次数是存在上限和下限的
规则2表明这些尝试总是希望获得最长的匹配。它们总是尝试匹配尽可能多的字符串,直到匹配上限为止。
例如:用'[0-9]+'匹配'TangJia19900326'能匹配字符串中的所有数字,这是因为1匹配成功之后,已经满足了匹配
成功的下限了,但此时正则表达式是匹配优先的,所以它会继续匹配完所有的数字。
过度的匹配优先:
'^.*([0-9](0-9))'匹配过程:由于标准量词优先原则,'.*'会直接匹配完整行,此时'([0-9][0-9])在尝试匹配时会失败,这样它就会强迫'.*'交出
一些字符供自己匹配,但这种‘强迫’是建立在不破坏'.*'匹配成功的条件之上的。
例如,用上述表达式匹配'about a 25 girl chen','.*'匹配整个字符穿后,第一个'[0-9]'的匹配要求'.*'释放一个字符'n',但这并不能让'[0-9]'
匹配,所以必须继续交还字符'e',直到释放'5'。但不幸的是第一个'[0-9]'虽然匹配成功了,第二个'[0-9]'仍然不能匹配。为了匹配整个
正则表达式,此时必须释放'2'(给第一个匹配),第二个'[0-9]'开始匹配,并最后成功匹配到'5'。
思考:用'^.*([0-9]+)'来匹配'tang 2003' 括号会捕获到什么?
三)表达式主导和文本主导
NFA引擎:表达式主导
例如:用表达式'to(nite|knight|night)'匹配'...tonight...',表达式第一个元素是't',它将会重复尝试,
直到在目标字符串中找到't',找到后再在目标字符串中查找'o',找到后会在目标元素中依次尝试'nite','knight',
'night'三种可能匹配成功。尝试'nite'的过程和之前一样,一个字符一个字符地依次尝试。
DFA引擎:文本主导
回溯(Backtracking)
基本原理----略。两个重要原则:
1.对于匹配优先量词,会进行尝试,对于忽略优先量词,会跳过尝试
2.后进先出
忽略优先量词
用'<B>.*?</B>'来匹配:
<B>Billions</B> and <B>Zillions</B> of suns......
开始匹配'<B>'之后,'.*?'首先决定不匹配任何字符,因为他是忽略优先的。
于是控制权交给后面的'<'符号,此时遇到了字符串中的B无法匹配,控制权
交还给'.*?',表达式便匹配到了B,因为是忽略优先的,控制权再次交给'<',
在重复数次后,最终匹配到: ‘<B>Billions</B>’
但如果我们用该表达式匹配: ‘<B>Billions<B> and <B>Zillions</B> of suns......’
就会匹配到:‘<B>Billions<B> and <B>Zillions</B’,这不是我们想要的结果
我们可以用否定环视解决这个问题:
固化分组:(?>......)
使用'(?>......)'的匹配与正常匹配的差别在于,如果匹配进行到结构结束后(也就是闭括号之后),结构体中的所有备用状态都将会被抛弃。
例子: '(.dd(?>[1-9]?))d+'在固化分组内,量词能够正常工作,如果'[1-9]'不能匹配,正则表达式则会返回'?'留下的备用状态。
然后脱离固化分组,继续前进到'd+'。在这种状态下,当控制权离开固化分组时,没有备用状态需要放弃。
占有优先量词: ?+、 *+、 ++、 和{m,n}+
占有优先量词和匹配优先量词的差别:不交还已经匹配的字符。
环视中的回溯
略
多选结构也是匹配优先的吗?
1.对于大多数传统型NFA:按顺序匹配,前面的匹配成功就不尝试后面的。
2.少数DFA和POSIX NFA:匹配优先,尽可能匹配更多的字符。
四)NFA、DFA 和 POSIX
最左最长规则
NFA:按顺序来
DFA:匹配最长的