正则表达式引擎
分类:
- DFA: Deterministic Finite Automaton,确定型有穷自动机
- NFA: Non-deterministic Finite Automaton,非确定型有穷自动机
- Traditional NFA:常用的引擎,如Java,less,more,sed,python,...
- POSIX NFA
NFA的特性:捕获和引用、环视、优先匹配/忽略的量词
字符串由字符和位置组成,位置数总比字符数多一个
占有字符、零宽度
我们说子表达式是占有字符的,当:
1. 子表达式匹配的是字符(而非位置)并且匹配结果被保存时
我们说子表达式是零宽度的,当:
1. 子表达式匹配的仅仅是位置(而不是字符)
2. 子表达式虽然匹配的是字符但是没有保存匹配结果时
占有字符的子表达式间互斥,零宽度的子表达式间非互斥
顺序肯定环视 —— 实际匹配结果重叠时进行查找
语法:(?=Expression)
示例:
假设现在有一个字符串'11!22@33#'
我们想匹配的模式是'\d.'
,即查找所有数字跟上任意字符的子串
期望结果是['11','1!','22','2@','33','3#']
然俄,re.findall('\d.', '11!22@33#')
的返回结果却是['11','22','33']
这还得从控制权的转交和正则的传动讲起
由于环视是匹配位置不占有字符,可以这样:re.findall('(?=\d.)', '11!22@33#')
解释一哈:
表示我们从第一个位置(索引为0)开始进行搜索,顺序肯定环视要求该位置右边必须要满足一定的规则(这里是'\d.'
)该位置才是有效匹配的位置。由于环视子表达式是零宽度的,不论这个规则多长,下一次匹配的位置都是当前位置加一,从而实现对每个位置进行检查。
这里注意一个细节,环视表达式检查的是位置,所以就算匹配成功返回的也是位置(不是字符),所以上面的语句实际结果是['','','','','','']
,要捕获字符串需要使用捕获组对规则进行捕获,就像这样:re.findall('(?=(\d.))', '11!22@33#')