匹配优先量词:*、+、?、{num,num}
忽略优先量词:*?、+?、??、{num,num}?
重要说明:量词在正常情况下都是“匹配优先”的,即匹配尽可能多的内容;相反,忽略优先量词则会匹配尽可能少的内容、只需满足匹配的下限,就算匹配成功,两者的差异影响深远,十分重要!
正则表达式的匹配引擎分类:
传统型NFA:支持忽略优先量词
如何测试:拿[nfa|nfa.not]来匹配‘nfa.not’,若只匹配了nfa,说明是传统的nfa,否则要么是POSIX NFA,要么
是DFA
DFA与POSIX NFA的区分:DFA支持捕获型括号和回溯。
如何测试:用[x(.+)+x]来匹配形如“=xx========”的字符串,若执行时间很长,就是NFA,若时间很短则是DFA或
是支持默写高级优化的NFA,如果现实堆栈超溢、或是超时退出,他就是NFA引擎。
正则匹配中的两则普适原则:
1、优先选择最左端(最靠开头)的匹配结果
2、标准的匹配量词([*]、[+]、[?]和[{m,n}])是匹配优先的。
解析:
第一条规则
这条规则的由来:匹配先从需要查找的字符串的起始位置尝试匹配。在这里“尝试匹配(attempt)”的意思是,在当前位置测试整个正则表达式(可能很复杂)能匹配的每样文本。如果在当前位置测试了所有的可能之后不能找出匹配的结果,就需要从第二个字符之前的位置开始重新尝试,在找到匹配结果之前必须在所有的位置重复此过程。只有在尝试过所有的起始位置(知道字符串的最后一个字符)都不能找到匹配结果的情况下,才能报告“匹配失败”。
第二条规则 标准量词是匹配优先的
首先:标准的匹配量词([*]、[+]、[?]和[{m,n}])都是匹配优先的。
如果用这些量词来约束某个表达式,在匹配成功之前,进行的尝试次数是存在上限和下限的,而规则2表明,这些尝试总是希望 获得最长的匹配。
简而言之,标准匹配量词(这里是指单个匹配量词,而不是整个正则表达式,从下面的例子中可以看出)的结果“可能”并非所有可能中最长的,但他们总是尝试匹配尽可能多的字符,直到匹配上限为止。如果最终结果并非该表达式的所有可能中最长的,原因肯定是匹配字符过多导致匹配失败,故不能取最长的。
例如:[\b\w+s\b]来匹配包含‘s’的字符串,如‘regexes’,[\w+]完全能够匹配整个单词,但如果用[\w+]来匹配整个单词,[s]就无法匹配,即会匹配失败,为了完成匹配,[\w+]必须匹配‘regexes’,把最后的[s\b]留出来。
零匹配的情况
如果表达式的其他部分能够成功匹配的唯一条件是:匹配优先的结构不匹配任何字符,在容许零匹配的情况下(如*、?、或{0,max})这是没有问题的,不过,这种情况只有在表达式的后续部分强迫下才能发生。
匹配优先量词之所以得名,是因为他们总是(或者说至少是尝试)匹配多于匹配成功下限的字符
最后,列举一个超级容易让人理解的例子,有关[.*]*让出一部分字符的情况
用[^.*([0-9]+)]匹配‘copyright 2003.’括号会捕获到什么?
答案:3,没错,只会捕获到3
因为:为了满足[0-9]+的匹配,‘.*’必须交出一些字符,在这个例子里‘.*’交出的是3和‘.’,之后3能够由[0-9]匹配,因[0-9]用+修饰,所以现在只做到了最小的匹配可能,现在他遇到了‘.’,找不到其他可以匹配的字符了。
与之前让出3不同,现在没有“必须”匹配的元素,因为[0-9]+已经做到了最小的匹配可能,所以‘.*’不会再*交出0,因为“先来先服务”的原则,匹配优先的结构只会在“*”的情况下交还字符,所以最后([0-9]+)只能匹配到3.