回溯的原理:记录所有可能的表达式分支,尝试匹配,若失败则返回,选择上次正确标记处按新的表达式(备用状态)开始新的尝试匹配。
可以回溯到特性:优先匹配、忽略优先的匹配、多选结构、环视、条件判断、反向引用、固化分组
回溯的两条原则: 1、进行尝试:匹配优先量词(?、*、+、{m, n}) 2、跳过尝试:忽略优先量词(??、*?) 强制回溯时候,执行“后进先出”原则,即从右向左进行回溯忽略优先 【例子】「ab??c」匹配「abc」 初始状态:「a,b??c」+「a,bc」–「a」与「a」匹配成功 备用状态:「ab??,c」+「a,bc」–「c」与「b」局部匹配不成功,回溯 回溯状态:「a,b??c」+「a,bc」–「b」与「b」匹配成功 备用状态:「ab??,c」+「ab,c」–「c」与「c」匹配成功
当优先量词为?时,设置一个备用状态,然后进行一次匹配,【设定备用状态时候】总是首先将上一个状态中表达式控制权后移(即可跳过?控制的字符),而上一个状态的文本位则保持不变,然后用表达式去检查文本是否匹配,分2种情况,优先匹配或优先忽略: 1-【优先匹配时候】【若匹配】备用状态中的文本检查位向后推动,【若不匹配】回溯到备用状态
2-【忽略优先匹配时候】【若匹配】表达式和文本继续正常匹配,【若不匹配】回溯到备用状态,即去匹配忽略的表达式
1、由于*表示任意次的匹配,因此需要不断保存备用状态,指导所有的规定字符被取完。 2、由于‘+’表示至少1次,因此需要首先找到一个成功匹配的字符,由此开始建立备用状态。
处于前边位置的分支匹配成功后,后边的分支将被忽略,所以需要按顺序排列,应该明确指导各个分支的先后次序 【例子】匹配日期:类似 Jan 31
【解析】 1、可能存在的形式: Jan 01、Jan 1、Jan 23 2、数字部分需要用多选分支来解决: Jan (0?[1-9]|[12][0-9]|3[01])
【目的】在某个字符匹配成功的情况下,放弃回溯,即放弃之前的备用状态,不会回退,方法有两种——固化分组和占有优先量词 1、固化分组——(?>…)
在这个结构体结束之后,放弃该结构体的备用状态,之前匹配内容固化为一个单元,作为整体保留或放弃,是一种“锁定”状态。
与匹配优先或忽略优先的”区别“是固化分组放弃了表达式中某些可能的分组,不进行回溯,导致一些结果:
(1)没有影响 (2)导致匹配失败 (3)改变匹配结果 (4)加快匹配失败的速度:比如用「\w+:」去匹配”Number“,显然不能匹配成功,但是表达式会做回溯而影响速度,因此,「(?>\w+):」可以放弃回溯,更快匹配失败
2、占有优先量词 占有优先量词:?+、*+、++和{m, n}+ 占有优先量词匹配时候不会产生备用状态,类似于固化分组,但是可以简化书写: (?>\w+:)与\w++:表达相同的含义
【例子1】用「.*([0-9][0-9])」匹配文本”I have 12345 dollors”
匹配结果:I have 12345,捕获45【解析】「.*」表示匹配任意文本或空白,即文本全部匹配,但是当正则表达式获得([0-9][0-9])的控制权后,’s’不能匹配第一个[0-9],需要进行回溯,文本回溯到“r”,仍然不能匹配,一直回溯到“5”满足第一个[0-9],第二个不能匹配,继续回溯到“45”,匹配成功。
【例子2】匹配双引号之间的文本
My dog’s name is “John”, its brother’s name is “Jack”.
【解析】 1、如果用「“.*”」来匹配,得到的结果是”John”, its brother’s name is “Jack”,显然不符合要求 2、所以应该把中间的双引号找到,获得非双引号之外的文本:「”[^”]*”」 3、此法叫“排除型字符组”,还可以使用忽略优先量词
【例子3】匹配“多字符” 匹配HTML的tag时候,获取< p >I have 12345 dollors< /p> and < p >you are 12< /p>中< p >与< /p>之间的内容
【解析】 1、类似与上个例子中的双引号,这里是< p>与< /p> 2、使用忽略优先匹配量词*? 3、「< p >.*?< /p>」