最近没事作研读了一下正则表达式,感觉很有意思的。很多特性grep ,awk ,sed 是不支持的,些特性都是基于NFA引擎的正则表达式,如perl 5 ,PHP 等语言都支持。
一、固化分组 (?>) 基于DFA 引擎的正则表达式不支持
简单点讲固化分组目的就是为了不让引擎回溯,从而提高效率。
看一个例子 m/(?>.*)a$/ 这里是想匹配a结尾,但这里什么都匹配不到,因为.* 已经吃掉所有的字符并且不回溯,a就不会匹配成功。所以在固化分组中不能用.* ;再看(?>.*?)这里什么也没有匹配,因为*?是忽略优先就是优先什么都不匹配并且放弃备用状态。
再看一例 m/<html>(?>[^<]*)(?>(?!</?html>)<[^<]*).*?</html>/ 相信很多朋友对这个都很熟悉,这里是想匹配<html>...</html>
先看(?>[^<]*) 这里是想听掉 非< 之前的所有字符 ;(?!</?html>)<[^<]* , (?!</?html>)<这是右否定环视,意思是 < 右边边不能是</?html>
二、回溯
DNA 没有回溯所以新效率很高,在NFA 中要尽量避免.比如可以用固化分组或懒惰性如 *? ,+?, ?? ,{}?
三、多选结构的最左匹配结果
DFA 引擎返回的是最优的匹配结果,但NFA引擎比较急总是返回最左匹配的结果
如 $str = "Jan 31" $str =~ (Jan ([0-2]?[1-9]|[123][01])) 这里返回的是Jan 3 因为[0-2]?[1-9] 最先匹配到的是3 ,所在在多选结构时要把最长的也就是最想匹配的结果表达式放在最前 如 /(Jan ([123][01]|[0-2]?[1-9]))/
四、忽略优先
忽略优先对应的是匹配优先 ,忽略优先的题词有*? , +? , {}? ,?? ,使用忽略优先可以避免回溯
五、环视
环视有: 左肯定环视 ,左否定环视, 右肯定环视 ,右否定环视
环视不占有匹配字符,它只是指定字符的位置。
左肯定环视 :(?<=) 如 (?<=<html>) 这里指左边位置存在<html>字符串
左否定环视 :(?<!) 如 (?<!<html>) 这里指左边位置不能存在<html>字符串
右肯定环视 :(?<) 如 (?=<html>) 这里指右边位置存在<html> 字符串
右否定环视 :(?!) 如 (?!<html>) 这里指右边位置不能存在<html> 字符串
六、单行模式与多行模式
单行模式也就是点通模式 ,主要是因为是最期版本 . 不能匹配/n ,现在为了能让.也能匹配 /n,就提出了单行模式 即加/s修饰符。m/../s
多行模式也就是增强的行锚点模式,我们知道^ $ 分别只能匹配字符串的 开始和结束位置,如果想让其能匹配每一行的开始和结束位置也是就/n的前后位置。这就要用到多行模式 即加/m修饰符, m/../m 。再说一下/A, /A在任何模式下只能匹配字符串的开始位置, /Z则要以匹配行的结束和字符串的结束位置,而/z 只能匹配字符串的结束位置。
七、锚定
锚定除了上面说的^ $ /A /Z /z再说一下/b ,/b是单词 的边界符锚定 如:
$str = 'hello he' ; $str =~ s/(/bhe/b)/this/g ; print $str 结果是hello this 而不是thisllo he