正则表达式匹配原理

匹配原理

了解正则匹配原理前,我们先看一下正则匹配引擎。正则表达式引擎主要有两种: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次以上,但尽可能少重复

你可能感兴趣的:(正则表达式)