python正则基础入门篇-2

这篇写关于分组(更多叫子表达式)和断言的一些概念和基本使用规范。

分组的符号是"()"一对括号,分组匹配的内容会分配到的每个括号里,一般会按照从左到右分配,1为第一个括号

#以一个例子简单熟悉下分组的作用
s='<div><a href="https//support.google.com/chrome/?p=ui_hotword_search" target="_blank">更多</a><p>dfsl</p></div>'
pattern1 = re.search(r'<a.*>(\w+)</a>',s).group()
pattern2 = re.search(r'<a.*>(\w+)</a>',s).group(0)
pattern3 = re.search(r'<a.*>(\w+)</a>',s).group(1)
pattern4 = re.search(r'<a.*>(\w+)</a>',s).groups()
print(pattern1)
print(pattern2)
print(pattern3)
print(pattern4)
#这里对应group(),默认会打印整个正则表达式
<a href="https//support.google.com/chrome/?p=ui_hotword_search" target="_blank">更多</a>
#这里对应group(0), 跟group()相同,都是打印整个正则
<a href="https//support.google.com/chrome/?p=ui_hotword_search" target="_blank">更多</a>
#这个就是分组1匹配到的内容
更多
#对应groups(),这个是将整个分组匹配到的内容输出成元组形式
('更多',)

 熟悉了分组后,我们需要面对一个现实问题,就是分组量太多的话,无法快速定位到分组量,所以又引出一个自定义分组的功能

 以(?P<组名>pattern)为分组格式,这样只用匹配组名就定位到该分组。

 实际演练:

#提取Ip地址
s = "ip='230.192.168.78',version='1.0.0'"
#自定义了一个“G”的组
matcher = re.search(r"ip='(?P<G>\d+\.\d+\.\d+\.\d+).*",s)
#直接定位匹配
print(matcher.group('G'))
#out
230.192.168.78
 

 加深对分组的理解:正则表达式中用"()"表示一个分组,然后你可以对这个分组进行操作,最常用的就是重复操作。

 要注意的是,只有"()"才能定义组,"{}"用来定义重复操作

 当用"()"定义一个正则表达式后,正则引擎会把这些"()"按照顺序编号,存入缓存。这样后续需要对组操作就可以直接引用,看到的"\1、\2"就是对之前的分组重复引用,值得注意

 的是"\0"是正则字符串本身。

 加深理解:

#利用交换字符串位置
s1 = "abc.def"
sb = re.sub(r'(\w+)\.(.*)',r'\2.\1',s1)
print(sb)
#利用分组后向引用,这样就可以直接在后面用\number引用,无需书写完整分组内容
#首先模拟不用后向引用
s2 = 'go go go'
pattern = r'(?P<name>\w+)\s+(?P=name)\s+(?P=name)'
mat = re.search(pattern,s2)
print(mat.group('name'))
print(mat.group(1))
# print(mat.group(2)) # 报错,因为只定义了一个组,后面是引用定义的,并没有新增
# print(mat.group(3)) # 同理
print(mat.groups())  # 将匹配到的分组结果输出成一个元祖
print(mat.group(0))  # 这个不解释了,打印整个r'表达式'

 接下采用后向引用  

pattern1 = r'(?P<new>.+)\s\1\s\1'
mat2 = re.search(pattern1,s2)
print(mat2.groups())  #输出匹配的所有组
print(mat2.group())   #输出整个正则表达式Regular_expression
#output 输出结果很明显得到了,组的结果和整个正则
('go',)  
go go go

# 从网上找了一个对边界匹配的例子,要求捕获"go go"
s = 'come on go go geek'
parttern= r'\b(.*)\b\s+\b\1\b\s+'
print(re.findall(parttern,s)) #输出匹配的分组,列表
print(re.search(parttern,s).groups()) #输出匹配的分组,元祖
print(re.search(parttern,s).group(1)) #输出第一组
print(re.search(parttern,s).group())  #输出整个表达式结果
parttern1 = r'\b(\s)\b'
print(re.search(parttern1,s).groups())  #输出所有分组,元组,可以看到匹配到了空格,但是java中好像\s不算是边界
#out
['go']
('go',)
gogo
go
(' ',)

-------------------------------

-------------------------------

 接下来讨论断言,其实跟分组很像,但是用法上跟分组用法恰好相反,由于分组学问很多,我只写一些基本的

 --前后肯定断言,基本格式:前肯(?= patt)、后肯(?<= patt)

 一样,实例 (注:前后肯定断言同时使用,后向需提前,后前包裹)

# 这里对长字符串中文本进行提取,前后定向正则规定在这个范围内匹配  
s = "/* hi! */this is girl /* shi is beautiful */ she have 168 cm"
partten =  r'(?<=/\*).*(?=\*/)'  # 这里必须加上"?",否则会贪婪模式多匹配,无视前向断言。
print(re.findall(partten,s))
...
# output  贪婪
[' hi! */this is girl /* shi is beautiful ']  
# output2 惰性
[' hi! ', ' shi is beautiful ']

--前后否定断言,基本格式: 前否(?! = patt) 后否 (?<!)

学习下:

#后否定断言实例,获取除了".txt"结尾的文件集
#这里用到了后向否定断言,否定结尾字符非txt。
f1 = 'aaa.txt'
partten = r'.*\..*$(?<!txt$)'
print(re.findall(partten,f1)   )
#output  因为f1是txt结尾,所以没有匹配到,返回空列表
[]
#前向否定断言匹配 开头非数字的文件集
f1 = 'aaa.txt'
# "?!"表示非,"\d+"表示至少一个数字,^()表示以之前的规则开头,整体理解:文件开头一个数字都没有的文件集
print(re.findall(r'^(?!\d+).*','1word.txt')) #这里"1"打头自然符合了前非的规则,被排除
print(re.findall(r'^(?!\d*).*',f1)) #这里区别于"+","*"至少0个数字,由于f1是字母开头(没有数字正好是0),被前否排除
print(re.findall(r'^(?!\d+).*',f1)) #这里区别于"*","+"至少一个数字,加前否成一个数字都没有的文件名,对应下面输出
#out 发现三个结果,值得仔细思考下
[]          
[]
['aaa.txt']

  前后向否定断言确实有点绕,很烧脑,可能是本人逻辑思维能力问题,但是可以大致这样理解,就是前后否定断言总体逻辑是 排除partten,就是除了的意思。可以这么理解。

# 提取不以数字开头和py结尾的文件
n = 'test.py'
m = 'test.txt'
print(re.findall(r'^(?!\d+).+\..*$(?<!py$)',n))
#output  由于前后断言必须满足才会输出,但是前向满足,后向不满足,因为py被后向排除
[]
print(re.findall(r'^(?!\d+).+\..*$(?<!py$)',m))
#out 很明显,前向否定断言否定至少有一个数字开头的文件,后否否定py结尾,test.txt都不包括,所以被匹配到
['test.txt']

整个断言分组基础就这么多内容,后续会对更复杂的断言进行练习。

参考:https://www.cnblogs.com/misswjr/p/9852574.html

 

 

posted @ 2020-05-09 15:49  周_游  阅读(151)  评论(0)    收藏  举报