后向引用:
默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1
代表分组1匹配的文本
# 匹配字符串中连续出现的两个相同的单词
>>> a = '111'
>>> re.search('(.)\\1\\1',a)
<_sre.SRE_Match object; span=(0, 3), match='111'>
#同样也可以用原生字符串来匹配
>>> re.search(r'(.)\1\1',a)
<_sre.SRE_Match object; span=(0, 3), match='111'>
`
自定义名称的后向引用:
s = 'hello blue go go hello'
p = re.compile(r'\b(?P<t_test>\w+)\b\s+(?P=t_test)\b')
print(re.findall(p,s))
贪婪与懒惰:
匹配的时候又分为两种模式 叫做贪婪模式/非贪婪模式,其中非贪婪模式又叫做懒惰模式
>>> re.search('<div>(.*)</div>',a)
<_sre.SRE_Match object; span=(0, 23), match='<div>aaa</div>bbb</div>'>
>>> re.search('<div>(.*?)</div>',a)
<_sre.SRE_Match object; span=(0, 14), match='<div>aaa</div>'>
>>> re.search('<div>(.*)</div>',a) #这时候先匹配到</div>的时候会继续往后匹配 如果还有</div>的话 那就继续匹配 通通都要
>>> re.search('<div>(.*?)</div>',a) #这个就与上面的相反 如果匹配到了</div> 那么就直接结束匹配
环视(断言/零宽断言):
环视,在不同的地方又称之为零宽断言,简称断言。
用一句通俗的话解释:
环视,就是先从全局环顾一遍正则,(然后断定结果,)再做进一步匹配处理。
断言,就是先从全局环顾一遍正则,然后断定结果,再做进一步匹配处理。
两个虽然字面不一样,意思却是同一个,都是做全局观望,再做进一步处理。
环视的作用相当于对其所在位置加了一个附加条件,只有满足这个条件,环视子表达式才能匹配成功。
环视主要有以下4个用法:
(?<=exp)
匹配前面是exp的数据
(?<!exp)
匹配前面不是exp的数据
(?=exp)
匹配后面是exp的数据
(?!exp)
匹配后面不是exp的数据
示例:
用python的re模块给大家做试验了哈
(?<=B)AAA
匹配前面是B的数据,即BAAA匹配,而CAAA不匹配
(?<!B)AAA
匹配前面不是B的数据,即CAAA匹配,而BAAA不匹配
AAA(?=B)
匹配后面是B的数据,即AAAB匹配,而AAAC不匹配
AAA(?!B)
匹配后面不是B的数据,即AAAC能匹配,而AAAB不能匹配
另外,还会看到(?!B)[A-Z]
这种写法,其实它是[A-Z]
范围里,排除B
的意思,前置的(?!B)
只是对后面数据的一个限定,从而达到过滤匹配的效果。
例子: 需求:字母、数字组合,不区分大小写,不能纯数字或者纯字母,6-16个字符。
通用正则:^[a-z0-9]{6,16}$
字母数字组合,6-16个字符
排除纯字母:(?!^[a-z]+$)
排除纯数字:(?!^[0-9]+$)
组合起来:(?!^[a-z]+$)(?!^[0-9]+$)^[a-z0-9]{6,16}$
re.search('(?!^[a-z]+$)(?!^[0-9]+$)^[a-z0-9]{6,16}','qq1352483315')
注意,环视部分是不占宽度的,所以有零宽断言的叫法。
所谓不占宽度,可以分成两部分理解:
1、环视的匹配结果不纳入数据结果
2、环视它匹配过的地方,下次还能用它继续匹配。
第一点如何理解呢?我讲下我自己的理解
简单的来说 就是环视匹配的表达式匹配到的数据在整个正则表达式中匹配的数据中是不存在的。
比如:
>>> a = 'ABBB'
>>> re.search('(?<=A)BBB',a)
<_sre.SRE_Match object; span=(1, 4), match='BBB'>
>>>
>>> a = 'ABBB'
>>> re.search('[A]BBB',a)
<_sre.SRE_Match object; span=(0, 4), match='ABBB'>
正常的正则匹配能够匹配到ABBB
,但是在环视中 我们在ABBB
中匹配到的却是BBB
不包含本身A
这就是第一个要点的解释!
第二点的解释:re.search('(?!^[a-z]+$)(?!^[0-9]+$)^[a-z0-9]{6,16}','qq1352483315')
大家可以看下这条表达式 我们通过这条表达式 来获取了
1、不可以全是数字
2、不可以全是字母
3、必须是数字和字母混合 并且长度为{6,16}
前面的(?!^[a-z]+$)
(?!^[0-9]+$)
这两条环视的表达式 是先环视一遍 然后才开始后面的匹配 所以说环视的时候是还可以继续匹配 一个例子简单的说明:我们一共要跑400米 你跑了100米来拿东西 拿完东西然后又回到起点 才真正的开始计时自己的400米所要跑的时间
一个拓展部分:
扩展部分:
`[A-Z](?<=B)` [A-Z]范围等于B
`[A-Z](?<!B)` [A-Z]范围排除B
`(?!B)[A-Z]` [A-Z]范围排除B
平衡组:
看不懂,等自己需要的时候再去学~
模式修饰符:
模式修饰符在许多程序语言中都支持的,比如最常见的是i,不区分大小写,如javascript里的/[a-z0-9]/i
,表示匹配字母数字,不区分大小写。
又或者是python中的正则表达式中的re.I又或者是re.S
其实意思都是相通的 re.I
对大小写不敏感和re.S
支持.
来匹配换行
举个例子:
a = 'abc'
re.search('(?i)[A-Z]+c')
结果:
<_sre.SRE_Match object; span=(0, 3), match='abc'>
又或者是
>>> re.search('[A-Z]+',a,re.I)
结果:
<_sre.SRE_Match object; span=(0, 3), match='abc'>
这个也就是可以说明对大小写不敏感了
其他的模式修饰符 大家还可以自行学习