表达式中的分组
它是可以通过" () "来进行分组,更专业的表达就是捕获组,每个完整的" () "可以分为一组,同时," () "中还可以嵌套" () ",即组之间还可以存在更小的组
概念
1、当我们在一个正则表达式中使用一个括号的话,就可以将一个需要进行匹配的字符串进行分组,将我们匹配的字符串进行分离处理。一般要分多组的话,左括号从左到右从1开始编号。
2、我们也可以简单的使用正则表达式,在正则表达式中还可以对分组自身进行引用。分组简化正则表达式,分组的右侧可以通过分组的编号引用分组匹配的子串。还可以将分组看成是一个整体,在分组的后面可以加量词,这个量词的作用域就是整个分组
go
import re
m = "(([1-9])\d*)([a-z]{2})"
r = re.match(m,"2246pq")
if r !=None:
print(r.groups()) # >>('2246', '3', 'pq')
print(r.group(0)) # >>2246pq
print(r.group(1)) # >>2246
print(r.group(2)) # >>3
print(r.group(3)) # >>pq
go
# 导入re模块
import re
tel = "0755-98776754"
# 定义正则表达式
pattern = "(\\d{4})-(\\d{8})"
result = re.search(pattern, tel)
print(result) # <re.Match object; span=(0, 13), match='0755-98776754'>
print(result.group()) # 0755-98776754
print(result.group(1)) # 0755
print(result.group(2)) # 98776754
print(result.groups()) # ('0755', '98776754')
其他功能函数
- \:表示转义字符,让正则表达式中的字符失去原有的意义
- .:表示匹配除了换行之外的任意字符,.就表示一个普通的符号,而不是正则表达式中的.
- |:表示或者,正则表达式1|正则表达式2|正则表达式3,只要满足其中一个正则表达式即可
go
# 导入re模块
import re
print(re.search("goog\\.le", "goog.le")) # <re.Match object; span=(0, 7), match='goog.le'>
print(re.search("cd|ef|mn", "133cd987")) # <re.Match object; span=(3, 5), match='cd'>
print(re.search("cd|ef|mn", "133mn987")) # <re.Match object; span=(3, 5), match='mn'>
re.compile() 表示编译正则表达式,用于提高正则匹配的效率
go
# 导入re模块
import re
str = "010-98766789"
# 定义正则表达式,使用re.compile() 进行编译
pattern = re.compile("(\\d{3})-(\\d{8})")
print(pattern.findall(str)) # [('010', '98766789')]
re.split() 使用指定的正则表达式切割
go
# 导入re模块
import re
print(re.split("\\d", "hello123world987welcome999")) # ['hello', '', '', 'world', '', '', 'welcome', '', '', '']
re.sub() 或者 re.subn() 使用指定的符号替换内容,re.subn() 会现实替换的次数,re.sub不会显示
go
# 导入re模块
import re
str1 = "今天 天气 好晴朗,这样的 天气适合出去 游玩......"
print(re.sub("\\s+", "+++", str1)) # 今天+++天气+++好晴朗,这样的+++天气适合出去+++游玩......
print(re.subn("\\s+", "+++", str1)) # ('今天+++天气+++好晴朗,这样的+++天气适合出去+++游玩......', 4)
分组--可以让我们从文本内容中提取指定模式的部分内容
通过group()和groups()来获取分组的内容
分组命名
命名分组就是给具有默认分组编号的组另外再给一个别名。命名分组的语法格式如下
(?P正则表达式)#name是一个合法的标识符
提取字符串中的ip地址
go
>>> s = "ip='230.192.168.78',version='1.0.0'"
>>> re.search(r"ip='(?P<ip>\d+\.\d+\.\d+\.\d+).*", s)
>>> res.group('ip')#通过命名分组引用分组
'230.192.168.78'
分组引用
分组的后向引用,当我们想要在正则表达式中引用前面的分组时,可以通过"\数字"的方式或者通过命名分组"(?P=name)"进行引用。使用数字时,如\1表示引用第一个分组,\2引用第二个分组...\n表示引用第n个分组
后向引用
go
#通过命名分组进行后向引用
>>> re.search(r'(?P<name>go)\s+(?P=name)\s+(?P=name)', 'go go go').group('name')
'go'
#通过默认分组编号进行后向引用
>>> re.search(r'(go)\s+\1\s+\1', 'go go go').group()
'go go go'
交换字符串的位置
go
>>> s = 'abc.xyz'
>>> re.sub(r'(.*)\.(.*)', r'\2.\1', s)
'xyz.abc'
前向肯定断言、后向肯定断言
前向肯定断言的语法:(?=pattern)
后向肯定断言的语法:(?<=pattern)
需要注意的是,如果在匹配的过程中,需要同时用到前向肯定断言和后向肯定断言,那么必须将后向肯定断言写在正则语句的前面,前向肯定断言写在正则语句的后面,表示后向肯定模式之后,前行肯定模式之前。
如:获取c语言代码中的注释内容
go
>>> s1='''char *a="hello world"; char b='c'; /* this is comment */ int c=1; /* t
his is multiline comment */'''
>>> re.findall( r'(?<=/\*).+?(?=\*/)' , s1 ,re.M|re.S)
[' this is comment ', ' this is multiline comment ']
(?<=/)这个是后向肯定断言,表示"/ "之后。(?=/)这个为前向肯定断言,表示" /"之前,这两合并起来就是一个区间了,所以后向肯定断言放在前向肯定断言前面
前向否定断言、后向否定断言
前向否定断言语法:(?!pattern)
后向否定断言语法:(?<!pattern)
go
#提取不是.txt结尾的文件
f1 = 'aaa.txt'
re.findall(r'.*\..*$(?<!txt$)',f1)
[]
#提取不以数字开头的文件
re.findall(r'^(?!\d+).*','1txt.txt')
[]
#提取不以数字开头不以py结尾的文件
re.findall(r'^(?!\d+).+?\..*$(?<!py$)','test.py')
[]
re.findall(r'^(?!\d+).+?\..*$(?<!py$)','test.txt')
['test.txt']