四.匹配分组
[元字符]分组符号
a|b 匹配字符a或 字符b (如果两个当中有重合部分,把更长的那个放前面)
(ab) 匹配括号内的表达式 ,将()作为一个分组
num 引用分组num匹配到的字符串
(?P)给分组命名
(?P=name)引用别名: 把name分组所匹配到的内容引用到这里
1.正常分组 ()
## (1) 正常情况下用()圆括号进行分组 可以用\1反向引用第一个圆括号匹配的内容。
## (2) (?:正则表达式)表示取消优先显示的功能
(正则表达式)把分组的匹配到的内容加到列表,不是分组的匹配匹配到的内容不加到列表中(?:正则表达式)把分组的匹配到的内容和没有分组匹配到的内容一起加到列表里
print(re.findall('.*?_good', 'one_good two_good three_good'))
# 注意从头开始的,然后进行匹配,匹配搭配_good开始不是任意字符
# ['one_good', ' two_good', ' three_good']
print(re.findall('(.*?)_good', 'one_good two_good three_good'))
# ['one', ' two', ' three']
# 在匹配的时候是需要_good才能符合匹配条件的,但是并没有加到列表中
# 只把分组匹配搭配的内容加入到列表中
print(re.findall('(?:.*?)_good', 'one_good two_good three_good'))
# 将匹配到的内容全部加到列表中,不管是分组内的还是分组外的
# ['one_good', ' two_good', ' three_good']
## (3)| 代表或
# 既想匹配abc 还要匹配 abcd
lst = re.findall("abc|abcd", "abc234abcd234390dbohdq")
print(lst)
# 有缺陷,不能够都匹配到
# ['abc', 'abc']
lst = re.findall("abcd|abc", "abc234abcd234390dbohdq")
print(lst)
# ['abc', 'abcd']
#对.匹配进行解析用\让原本有意义的字符变得无意义.代表任意字符,除了\n如果想要让正则匹配有个用\.让点的转义失效
# 匹配小数
# 231.321 3213 312 89.32 0.3231
lst = re.findall("\d+\.\d+", "231.321 3213 312 89.32 0.3231")
# \d+ 表示匹配一个或者多个数字
print(lst)
# ['231.321', '89.32', '0.3231']
# 使用分组的形式来匹配小数和正数
# 不正确版本,加入的是小数部分或空字符
lst = re.findall("\d+(\.\d+)?", "231.321 3213 312 89.32 0.3231")
print(lst)
# ['.321', '', '', '.32', '.3231']
# 正确版
lst = re.findall("\d+(?:\.\d+)?", "231.321 3213 312 89.32 0.3231")
print(lst)
# ['231.321', '3213', '312', '89.32', '0.3231']
# 从字符串中匹配135或171的手机号
print("=========================135")
lst = re.findall("(?:135|171)\d{8}", "135678987654w171skdjfksjkf 11312312317178787887")
print(lst)
lst = re.findall("135\d{8}|171\d{8}", "135678987654w171skdjfksjkf 11312312317178787887")
print(lst)
lst = re.findall("(?:135|171)[0-9]{8}", "135678987654w171skdjfksjkf 11312312317178787887")
print(lst)
# 结果都是:
# ['13567898765', '17178787887']
2.命名分组
## (3) (?P正则表达式)给这个组起一个名字## (4) (?P=组名)引用之前组的名字,把该组名匹配到的内容放到当前位置
import re
#首先是正常分组对这些内容的匹配及结果
strvar = '
lst = re.findall("(.*?)",strvar)
print(lst)
# [('h1', 'sdfsdfsdfsdf', '/h1')]
strvar = "123
lst = re.findall("(.*?)",strvar)
print(lst)
# [('h1', 'sdfsdfsdfsdf', '/h1'), ('h2', 'ppoo', '/h2')]
#反向引用,#拿到已经匹配到的值,再引用一次#引用第一个口号里面的内容\1#引用第二个括号里面的内容\2依次类推
#例:
strvar = "123
lst = re.findall(r"(.*?)\1>",strvar)
print(lst)
#findall能根据反向匹配,但是不显示在匹配后的数据里
# [('h1', 'sdfsdfsdfsdf'), ('h2', 'ppoo')]
#命名分组方式1:
strvar = 'd3j5sdj'
obj = re.search(r"(.*?)\d(.*?)\d(.*?)\1\2",strvar)
print(obj)
# <_sre.sre_match object span="(0," match="d3j5sdj">
res = obj.group() #对象.方法
print(res)
#search反向引用的数据也匹配到数据中,关于search说明请见正则相关函数
# 结果为: d3j5sdj
#命名分组方式2:
#用命名分组进行反向引用
obj = re.search("(?P.*?)\d(?P.*?)\d(?P.*?)(?P=tag1)(?P=tag2)",strvar)
print(obj)
# 得到的是一个对象: <_sre.sre_match object span="(0," match="d3j5sdj">
res = obj.group()
# 使用对象.方法 的到数据: d3j5sdj
print(res)
#命名分组方式3:
obj = re.search(r"(?P.*?)\d(?P.*?)\d(?P.*?)\1\2",strvar)
print(obj)
# <_sre.sre_match object span="(0," match="d3j5sdj">
res = obj.group()
print(res)
# 使用对象.方法 的到数据: d3j5sdj
五.正则相关函数
findall 匹配字符串中相应内容,返回列表[用法: findall("正则表达式","要匹配的字符串")]
search 通过正则匹配出第一个对象返回,通过group取出对象中的值
match 验证用户输入内容
split 切割
sub 替换
finditer 匹配字符串中相应内容,返回迭代器
compile 指定一个统一的匹配规则
1.findall
上面已经讲过不多做讲解
2.search
通过正则匹配出第一个对象返回,通过group取出对象中的值
Search通过正则匹配出第一个对象返回(只匹配一次),通过group取出对象中的值
findall把满足条件的所有值都找出来放到列表里面返回search找到一个满足条件的值就直接返回,扔到一个对象当中想要获取对象中的值,用group对象.group()
# 注意只匹配一次
obj = re.search("\d+", "dohd3093dhdoqhd9023")
# \d+ 表示匹配多次数字,到不符合停止,search只匹配一次所有是3093
print(obj) # 返回的是一个对象 #<_sre.sre_match object span="(4," match="3093">
res = obj.group()
print(res) # 3093
# 匹配www.baidu.com 或者 www.sohu.com
obj = re.search("(w{3})\.(baidu|sohu)\.(com)", "www.baidu.com www.sohu.com")
res = obj.group()
#虽然两个地址都符合条件,但是search只匹配一次
print(res)
#结果: www.baidu.com
obj = re.search("(www)\.(baidu|sohu)\.(com)", "www.sohu.com")
res = obj.group()
print(res) # www.sohu.com
# 数字1 代表第一个括号里面的内容
res = obj.group(1)
print(res) # www
# 数字2 代表第二个括号里面的内容
res = obj.group(2)
print(res) # sohu
# 数字2 代表第三个括号里面的内容
res = obj.group(3)
print(res) # com
# groups 一次性把所有小括号里面的内容匹配出来
res = obj.groups()
print(res) # ('www', 'sohu', 'com')
3.match验证用户输入内容
# search 和 match 用法一样,区别在于match 在正则的前面加了一个^条件 [必须以...开头]
# search 只需要在正则的前面加上^ 就可以取代 match
strvar = "uuyydfopopopop3434sdf234"
# obj = re.search("^d.*?",strvar) #等价于,match
obj = re.search("d.*?\d", strvar)
res = obj.group()
print(res) # dfopopopop3
# match
obj = re.match("d.*?\d", strvar)
print(obj) # None 必须以d作为字符串的开头,所有匹配不到返回None
# res = obj.group()
# print(res)
4.split切割
#例1:
#字符串的方法是将,替换成| 再用字符串切割用| 切割为列表
strvar = "one|two|three,four"
lst = strvar.replace(",","|").split("|")
print(lst)
#['one', 'two', 'three', 'four']
#使用re的切割方法
strvar = "one,two|three%four"
res = re.split(r"[,|%]",strvar)
#通过多个字符选一个匹配切割最后得到列表
print(res)
#['one', 'two', 'three', 'four']
#例2:
strvar = "one234234two2three909090four"
res = re.split(r"\d+",strvar)
# 通过用\d+ 为分界来切割,将得到的数据返回放入列表
print(res)
# ['one', 'two', 'three', 'four']
5.sub 替换
#格式: sub(pattern, repl, string, count=0, flags=0)
#例:
strvar = "one,two|three%four"
res = re.sub("[,|%]","-",strvar)
print(res)
# one-two-three-four
#后面可以选择替换的次数
#只替换一次
res = re.sub("[,|%]","-",strvar,1)
print(res)
# one-two|three%four
res = re.sub("[,|%]","-",strvar,count=1)
print(res)
# one-two|three%four
#subn 和 sub 用法一样,最大的区别在返回值,返回一个元组,包含替换的次数
res = re.subn(r"[,|%]","-",strvar)
print(res)
# ('one-two-three-four', 3)
6.finditer匹配字符串中相应的内容,返回迭代器
# finditer 和 findall 用法一样,区别在于返回的是迭代器
strvar = "sdfsdff&*&*%^%234sdfsdfskdjfk3sdf23"
#例:使用findall
lst = re.findall("\d", strvar)
print(lst) # ['2', '3', '4', '3', '2', '3']
#例:使用finditer
res = re.finditer("\d", strvar)
print(res) #
from collections import Iterator
print(isinstance(res, Iterator)) # True
it = re.finditer("\d", strvar)
#lst = list(it)
#print(lst)
obj = next(it)
res = obj.group()
print(res)
# 2
for i in it:
res = i.group()
print(res)
# 输出为: 3 4 3 2 3
7.compile 指定一个统一的匹配规则
写一套正则,程序就需要重新编译一次同一个正则多处使用,反复编译会浪费时间这样的话,就可以使用compile来定义,终身受益
#例:
rule = re.compile("\d+") #规则是匹配至少一次数字
print(rule) # re.compile('\\d+')
strvar = "sdfsdfs234kjkjk*(*9343dsf3"
# 用search 匹配至少一次数字贪婪算法知道不符合才停止
obj = rule.search(strvar)
# 获取一个对象
print(obj) # <_sre.sre_match object span="(7," match="234">
# 对象.方法得到数据
print(obj.group()) # 234
#使用规则用findall进行匹配
lst = rule.findall(strvar)
# ['234', '9343', '3']
print(lst)
六.正则表达式修饰符
常用修饰符说明:
re.I使匹配对大小写不敏感
re.M多行匹配,影响 ^ 和$
re.S使 . 匹配包括换行在内的所有字符
#例1:
strvar = """
# 不受大小写影响,和不受换行影响结合
lst = re.findall("^
print(lst) # ['sdfsf', 'dd22', 'aabb']
#例2:
strvar = """
#不受多行匹配影响
rule = re.compile("^
#rule = re.compile("^
lst = rule.findall(strvar)
print(lst)
print("===========")
#re.S 使.匹配包括换行在内的所有字符
obj = rule.search(strvar)
print(obj.group())
正则相关练习
import re
# 1、匹配整数或者小数(包括正数和负数)
lst = re.findall(r"[+-]*?\d+\.*?\d*?",'-555555 w3213 +321 321.321 321.321')
print(lst)
# 2、匹配年月日日期 格式 2018-12-31
lst = re.findall( '\d{4}-(?:0[0-9])-(?:[0-2]\d)|\d{4}-(?:0[0-9])-
(?:[3][0-1])|\d{4}-(?:1[0-2])-(?:[0-2]\d)|\d{4}-(?:1[0-2])-(?:[3][0-1])','2018-12-31 2018-09-02 2018-02-29 2018-10-31 qwhowq3056-13-24 2018-01-32')
print(lst)
# 3、匹配qq号 5-12 首字符没有0
import re
qqnum = input("请输入您的qq号:")
lst = re.findall('^[1-9]\d{4,11}$',qqnum)
if len(lst) == 0:
print("您输入的qq号格式有错误")
else:
print("您的qq号为:",lst[0])
# 4、11位的电话号码
import re
call_num = input("请输入您的电话号码:")
lst = re.findall("^[1-9]\d{10}$",call_num)
if len(lst) == 0:
print("您输入的手机号有误")
else:
print("您输入的电话号码是:",lst[0])
# 5、长度为8-10位的用户密码 : 包含数字字母下划线
import re
lst = re.findall('[\da-zA-Z_]{8,10}','js_28aAA')
print(lst)
# 6 写出4位验证码的正则匹配
import re
lst = re.findall('[\da-zA-Z]{4}','fF4n 1231 312313 dads12 123 d a ddd')
print(lst)
# 7、匹配邮箱地址 邮箱规则
# @之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.)
# @和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),且两个点不能挨着
# 最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于2个字节,小于等于6个字节
import re
lst = re.findall(r'[a-zA-Z\d\-\_\.]+@[a-zA-Z\d\.\-]+\.[a-zA-Z]{2,6}','[email protected] [email protected] [email protected]')
print(lst)
import re
# 8、从类似
# wahaha
# banana
#
#
# 这样的字符串中,
# 1)匹配出 wahaha,banana,qqxing 内容。
"
"""
import re
strvar = "
lst = re.findall("<.>(.*?)<.>",strvar)
print(lst)
re.search("<.>(.*?)<.>",strvar)
"""
import re
strvar= """wahaha banana
"""
lst1 = re.findall(r"<.>([^<>]{2,})<.>",strvar)
print(lst1)
# 2)匹配出 a,b,h1这样的内容
lst2 = re.findall(r"(.*?)>",strvar)
print(lst2)
lst3 = re.findall(r"",strvar)
print(lst3)
# 9.
print("========把字符串进行运算==========")
strvar = "5*6-7/3"
def suan(strvar):
strvar = strvar
lst = re.findall("(?:\d+)(?:[*/+-])(?:\d+)", strvar)
for i in lst :
obj = re.search("(\d+)([*/+-])(\d+)",i)
#res = obj.group()
#print(res)
if obj.group(2) == "*":
res = int(obj.group(1)) * int(obj.group(3))
#print(res)
elif obj.group(2) == "/":
res = int(obj.group(1)) / int(obj.group(3))
#print(res)
elif obj.group() == "+":
res = int(obj.group(1)) + int(obj.group(3))
#print(res)
elif obj.group(2) == "-":
res = int(obj.group(1)) - int(obj.group(3))
#print(res)
strvar = strvar.replace(i,str(res))
return strvar
strvar = suan(strvar)
print("=====1========")
print(strvar)
strvar = suan(strvar)
print("=====2========")
print(strvar)
# 10.计算器
import re
#计算乘除的方法
def parse_exp(exp):
if "*" in exp:
a,b = exp.split("*")
#print(a,b)
return str(float(a) * float(b))
if "/" in exp:
a,b = exp.split("/")
return str(float(a) / float(b))
#去除++ +- -- -+ bug 情况
def exp_format(exp):
#如果出现下面情况就替换相应的
exp = exp.replace("+-","-")
exp = exp.replace("--","+")
exp = exp.replace("-+","-")
exp = exp.replace("++","+")
return exp
#实际计算
def exp_calc(strvar):
#计算乘除
while True:
res_obj = re.search("\d+(\.\d+)?[*/][+-]?\d+(\.\d+)?",strvar)
if res_obj:
res = res_obj.group()
#print(res) #5*-2
res2 = parse_exp(res)
#print(res)
strvar = strvar.replace(res,res2)
else:
break
#print(strvar)
#计算加减
res = exp_format(strvar)
#print(lst)
lst = re.findall("[+-]?\d+(?:\.\d+)?",res)
#print(lst)
count = 0
for i in lst:
count += float(i)
#print(count)
return count
#去除括号
def remove_bracket(strvar):
while True:
#匹配出最里面一层的括号
res_obj = re.search("\([^()]+\)",strvar)
if res_obj:
res_exp = res_obj.group()
#print(res_exp)
#计算口号里面的值,exp_calc
res = str(exp_calc(res_exp))
#print(res,type(res))
#把算好的实际数值转换成字符串,替换以前的圆括号
strvar = strvar.replace(res_exp,res)
else:
#直接返回替换好的字符串
return strvar
#主函数
def main(strvar):
#先把所有的空格去掉
strvar = strvar.replace(" ","")
#去掉空格
res = remove_bracket(strvar)
#print(res)
#计算最后结果
return exp_calc(res)
a = '1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
res = main(a)
print(res)
#验证结果
res = eval(a)
print(res)