Python 基础之正则之二 匹配分组,正则相关函数及表达式修饰符
四.匹配分组
[元字符] 分组符号
a|b 匹配字符a 或 字符b (如果两个当中有重合部分,把更长的那个放前面)
(ab) 匹配括号内的表达式 ,将()作为一个分组
num 引用分组num匹配到的字符串
(?P<name>)给分组命名
(?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 = '<h1>sdfsdfsdfsdf</h1>'
lst = re.findall("<(.*?)>(.*?)<(.*?)>",strvar)
print(lst)
# [('h1', 'sdfsdfsdfsdf', '/h1')]
strvar = "123<h1>sdfsdfsdfsdf</h1> 123<h2>ppoo</h2>"
lst = re.findall("<(.*?)>(.*?)<(.*?)>",strvar)
print(lst)
# [('h1', 'sdfsdfsdfsdf', '/h1'), ('h2', 'ppoo', '/h2')]
#反向引用,
# 拿到已经匹配到的值,再引用一次
#引用第一个口号里面的内容 \1
#引用第二个括号里面的内容 \2 依次类推
#例:
strvar = "123<h1>sdfsdfsdfsdf</h1> 123<h2>ppoo</h2>"
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, 7), match='d3j5sdj'>
res = obj.group() #对象.方法
print(res)
#search反向引用的数据也匹配到数据中,关于search说明请见正则相关函数
# 结果为: d3j5sdj
#命名分组方式2:
#用命名分组进行反向引用
obj = re.search("(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar)
print(obj)
# 得到的是一个对象: <_sre.SRE_Match object; span=(0, 7), match='d3j5sdj'>
res = obj.group()
# 使用对象.方法 的到数据: d3j5sdj
print(res)
#命名分组方式3:
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)\1\2",strvar)
print(obj)
# <_sre.SRE_Match object; span=(0, 7), 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, 8), 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) #<callable_iterator object at 0x0000021398B5ACF8>
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, 10), match='234'>
# 对象.方法得到数据
print(obj.group()) # 234
#使用规则用findall进行匹配
lst = rule.findall(strvar)
# ['234', '9343', '3']
print(lst)
六.正则表达式修饰符
常用修饰符说明:
re.I使匹配对大小写不敏感
re.M 多行匹配,影响 ^ 和 $
re.S使 . 匹配包括换行在内的所有字符
#例1:
strvar = """<h1>sdfsf</H1>
<H1>dd22</h1>
<h1>aabb</H1>"""
# 不受大小写影响,和不受换行影响结合
lst = re.findall("^<h1>(.*?)</h1>$",strvar,flags=re.M|re.I)
print(lst) # ['sdfsf', 'dd22', 'aabb']
#例2:
strvar = """<h1>sdfsf</h1>
<h1>dd22</h1>
<h1>aabb</h1>"""
#不受多行匹配影响
rule = re.compile("^<h1>(.*?)</h1>$",flags=re.M)
#rule = re.compile("^<h1>(.*?)</h1>$",flags=re.M|re.I)
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}','1.9_05697@q.3q.com 1.9_05697@q.3q.com1234 9.j05697@q-.q.com6789')
print(lst)
import re
# 8、从类似
# <a>wahaha</a>
# <b>banana</b>
# <h1>qqxing</h1>
# <h1>q</h1>
# 这样的字符串中,
# 1)匹配出 wahaha,banana,qqxing 内容。
"<h1>(.*?)<h1>"
"""
import re
strvar = "<h1>qqxing</h1> <b>banana</b>"
lst = re.findall("<.*?>(.*?)<.*?>",strvar)
print(lst)
re.search("<.*?>(.*?)<.*?>",strvar)
"""
import re
strvar= """<a>wahaha</a> <b>banana</b> <h1>qqxing</h1> <h1>q</h1>
"""
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)
Python 基础之正则之二 匹配分组,正则相关函数及表达式修饰符的更多相关文章
- [002] - JavaSE面试题(二):基本数据类型与访问修饰符
第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [002] - JavaSE面试题(二):基本数据类型与访问修饰符 第1问:Java的数据类型有哪 ...
- Python基础学习笔记(二)变量类型
参考资料: 1. <Python基础教程> 2. http://www.runoob.com/python/python-chinese-encoding.html 3. http://w ...
- (Python基础教程之十二)Python读写CSV文件
Python基础教程 在SublimeEditor中配置Python环境 Python代码中添加注释 Python中的变量的使用 Python中的数据类型 Python中的关键字 Python字符串操 ...
- [原创] 基础中的基础(二):C/C++ 中 const 修饰符用法总结
在这篇文章中,我总结了一些C/C++语言中的 const 修饰符的常见用法,供大家参考. const 的用法,也是技术性面试中常见的基础问题,希望能够帮大家梳理一下知识,给大家一点点帮助.作者是菜鸟一 ...
- Python基础笔记系列十二:requests模块的简单应用
本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! httpbin httpbin这个网站能测试 HTTP 请求和响应的各种信 ...
- python基础之数据类型(二)
Python3 元组 Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 不可变的tupl ...
- Python基础学习参考(二):基本语法
一.基本语法 既然是学习一门语言,它肯定有区别与其它语言的语法规则,现在就来解释一下python的语法规则是什么? 注释:通过"#"可以对python进行注释,注意是单行注释,如果 ...
- python基础知识总结(二)
基础数据类型初始: int(数字):+ 加 - 减 * 乘 / 除 % 取余数 str(字符串):python中凡是用引号引起来的都是字符串 可以相加,用来表示字符串的拼接 可以相乘,只能 ...
- Python基础之面向对象进阶二
一.__getattribute__ 我们一看见getattribute,就想起来前面学的getattr,好了,我们先回顾一下getattr的用法吧! class foo: def __init__( ...
随机推荐
- 6_13古代象形符号(UVa1103)<图的连通块的应用>
给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符.然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号. 输出说明:For each test case, display its ...
- CentOS 7 下挂载NTFS盘及开机自动挂载
一.工具 NTFS-3G 二.安装2种安装方式 2.1.yum安装 yum install NTFS* 2.2.编译安装 下载 解压 wget https://tuxera.com/opensourc ...
- 解决android studio 3.5.3版本的下载安装问题 2.5日
有些好笑,我安装了android studio3.5版本的软件安装了四天,在刚开始的时候,同学们安装软件应该是一趟就下来了,但是我的软件一直卡在了 ERROR: Unable to find vali ...
- java 子线程异常处理
如何在父线程中捕获来自子线程的异常呢 方法一:子线程中try... catch... 方法二:为线程设置异常处理器UncaughtExceptionHandler (异常处理也是在子线程中执行,相当于 ...
- 移动端 输入框 input 被弹出来的键盘 挡住
给被挡住的input或者textarea加一个id,然后在click事件里调用下面的代码 document.querySelector('#xxx').scrollIntoView();
- 记录一下自己搭建springboot+mybatis+druid 多数据源的过程
前言 上次的一个项目(springboot+mybatis+vue),做到后面的时间发现需要用到多数据源.当时没有思路..后来直接用了jdbc来实现.这几天不是很忙,所以决定自己再搭建一次.不多说, ...
- 每天进步一点点------altium designer Summer09出现的问题解决方案
在编译原理图时,引脚和连线旁边出现很多红线,提示 error:signal with no driver. 原理图没有加入到Project里. 第一次导入没问题,但是改了个元件的封装,在更新一下(De ...
- 【REST详述及RESTful规范】
目录 Web服务交互 理解REST 什么是资源? 什么是URI.URL? 统一资源接口 资源的表述 状态转移 小结 "RESTful是一种软件的架构风格.设计风格,为客户端和服务端的交互提供 ...
- ACM的探索之Everything Is Generated In Equal Probability(这真的是很有趣的话语丫!)
---------------------------------------步履不停,奋勇前进! ------------------------难度真的是蛮大丫!后序补充!
- opencv:图形绘制与填充
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...