匹配原理
了解正则匹配原理前,我们先看一下正则匹配引擎。正则表达式引擎主要有两种:DFA 和 NFA。
- DFA(Deterministic finite automaton)确定型有穷自动机
- NFA(Non-deterministic finite automaton)非确定型有穷自动机
还有POSIX NFA,这个是根据NFA引擎出的规范范本,使用较少
引擎 | 区别 |
---|---|
DFA | 1、DFA是根据字符串字符,去正则表达式匹配,所以叫确定型(确定匹配顺序) 2、没有回溯,不可以捕获子表达式等,所以匹配速度相对较快 3、代表:awk、egrep、flex、MySql、Procmail |
NFA | 1、NFA以正则表达式为主导,去字符串表达式中匹配 2、有回溯算法(贪婪模式)、支持子匹配,因为回溯,所以速度可能很慢 3、一般高级语言使用NFA引擎:Java、JavaScript、less、more、Perl、PHP、Python、Ruby、sed、vi等 |
这里我们主要看一下NFA匹配原理。首先看一个匹配实例:字符串 new,正则表达式 /new/
NFA以正则表达式为主,首先拿n去字符串匹配。(对于new字符串,匹配引擎会标记为0n1e2w3,即0123四个位置和new三个字符。)从0位置开始匹配,匹配到字符n,然后引擎再拿正则里的e去继续匹配,此时e从位置1开始匹配,成功匹配e,再拿w从位置2匹配,匹配完成。
字符串 new,正则表达式 /n\w+w/
首先拿正则n去匹配字符串,同样从位置0开始,匹配成功。然后拿到\w+,从位置1开始匹配,这里\w+为贪婪模式,直接匹配字符串的ew,匹配成功。此时位置已经标记到了3。最后再拿到正则里的w去从字符串位置3开始匹配,匹配失败,这里回溯模式下会回溯一位,到位置2,然后再去匹配,匹配成功。
字符串 new, 正则表达式 /^(?=n)[a-z]+$/
首先拿到正则里的元字符^(^和$匹配位置),匹配位置0,然后拿到正则(?=n),这里是匹配当前位置是否是字符n,不占有字符,也不将匹配到的内容保存到匹配结果里,所以也叫零宽断言。注意,^和(?=n)都是匹配位置,都是零宽度,零宽度表达式之间不互斥,即同一个位置可以同时由多个零宽度子表达式进行匹配,所以(?=n)也是从位置0开始匹配,匹配到字符n。然后拿到[a-z]+,继续从位置0开始匹配。这里同样贪婪匹配到new三个字符,位置到达3。最后正则表达式拿到$,从位置3开始匹配,匹配完成。
上述匹配过程,我们有分析提到“占有字符”和“零宽度”。正则表达式匹配过程中,如果子表达式匹配到的是字符内容,而不是位置,则被保存的匹配结果中,我们就称这个子表达式是占有字符的。如果子表达式匹配的是位置,那匹配内容不会保存到结果中,我们称该子表达式是零宽度的。占有字符是互斥的,零宽度是非互斥。
匹配模式
一般正则表达式分两种匹配模式: 贪婪模式 & 非贪婪模式
当正则表达式中包含能接受重复的限定符时,通常是匹配尽可能多的字符,即默认贪婪模式。
相对贪婪模式,有时我们需要匹配尽可能少的字符,即懒惰匹配。一般在可重复限定符前面加问好?,即可转为懒惰模式匹配。
正则限定符 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或多次,但尽可能少重复 |
?? | 重复0或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。