re模块
在Python中需要使用正则表达式来进行字符串匹配的时候,需要用一个re模块
re模块的使用过程:
import re
# 使用match函数进行匹配
result = re.match(正则表达式, 要匹配的字符串)
# 如果上一步匹配到数据的话,可以用group来提取数据
result.group()
- re模块匹配示例
import re
result = re.match('itcast', 'itcast.cn')
result.group()
# 输出为itcast
re.match()能够匹配出以XXX开头的字符串
匹配单个字符
字符 | 功能 |
---|---|
. | 匹配任意1个字符(除了\n) |
[ ] | 匹配[ ]中列举的字符 |
\d | 匹配数字,即0-9 |
\D | 匹配非数字,即不是数字 |
\s | 匹配空白,即 空格,tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符,即a-z、A-Z、0-9、_、一些常用的汉字或者其他国家的语言可以匹配到,所以一般慎用 |
\W | 匹配非单词字符 |
- 示例
import re
ret = re.match('.', 'M')
print(ret.group())
ret = re.match('t.o', 'too')
print(ret.group())
ret = re.match('[h]', 'hello world')
print(ret.group())
ret = re.match('[hH]', 'Hello world')
ret = re.match('[12345678]hello world','2hello world')
ret = re.match('[1-36-9]hello world', '4hello world') # 在这里这个并不能被匹配到,因为这个匹配的范围是1-3和6-9两个范围,4并不在这个区间内
ret = re.match('[1-3hcduh]', 'h') # 也就是说在这个中括号内可以放数字和字母的混合
匹配多个字符
字符 | 功能 |
---|---|
* | 匹配前一个字符出现0次或者无限次,即可有可无 |
+ | 匹配前一个字符出现1次或者无限次,即至少有1次 |
? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有 |
{m} | 匹配前一个字符出现m次 |
{m,n} | 匹配前一个字符出现从m到n次 |
示例:*
需求:匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无
import re
ret = re.match('[A-Z][a-z]','M')
print(ret.group()) # 报错
ret = re.match('[A-Z][a-z]*, 'MnnM')
print(ret.group()) # MnnM
ret = re.match('[A-Z][a-z]*','Azbcdef')
print(ret.group(group)) # Azbcdef
示例2:+
需求:匹配出,变量名是否有效
import re
names = ['names','_names','2_names','__name__']
for name in names:
ret = re.match('[a-zA-Z_]+[\w]*', name)
if ret:
print('变量名 %s 符合要求'%ret.group())
else:
print('变量名 %s 非法'%name)
输出为:
变量名 names 符合要求
变量名 _names 符合要求
变量名 2_names 非法
变量名 __name__ 符合要求
示例3:?
需求:匹配出,0-99之间的数字
import re
ret = re.match('[1-9]?[0-9]', '7')
print(ret.group())
ret = re.match('[1-9]?\d', '33')
print(ret.group())
ret = re.match('[1-9]?\d', '9')
print(ret.group())
示例4:{m}
需求:匹配出,8-20位的密码,可以是大小写英文字母、数字、下划线
import re
ret = re.match('[a-zA-Z0-9_]{6}', '12a3g45678')
print(ret.group())
ret = re.match('[a-zA-Z0-9_]{8,20}', 'hdhfe63237dnjhf7e')
print(ret.group())
# 输出为
12a3g4
hdhfe63237dnjhf7e
匹配开头结尾
字符 | 功能 |
---|---|
^ | 匹配字符串开头,标记整个正则表达式匹配开始 |
$ | 匹配字符串结尾,标记整个正则表达式匹配结束 |
示例1:$
需求:匹配出163.com的邮箱地址
import re
email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]
for email in email_list:
ret = re.match('[\w]{4,20}@163.com', email)
if ret:
print('%s是符合规定的邮件地址,匹配的结果是:%s'%(email, ret.group()))
else:
print('%s不符合要求'%email)
运行结果:
xiaoWang@163.com是符合规定的邮件地址,匹配的结果是:xiaoWang@163.com
xiaoWang@163.comheihei是符合规定的邮件地址,匹配的结果是:xiaoWang@163.com
.com.xiaowang@qq.com不符合要求
xiaowang@163.comheihei很明显不符合邮箱地址的书写格式,但是运行结果显示符合,原因就是正则表达式只能判断出来以什么样的形式开头但是对后面的格式无从下手,这就需要一个符号专门标记正则表达式结束
完善后:
import re
email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]
for email in email_list:
ret = re.match('[\w]{4,20}@163\.com$', email)
if ret:
print('%s是符合规定的邮件地址,匹配的结果是:%s'%(email, ret.group()))
else:
print('%s不符合要求'%email)
运行结果:
xiaoWang@163.com是符合规定的邮件地址,匹配的结果是:xiaoWang@163.com
xiaoWang@163.comheihei不符合要求
.com.xiaowang@qq.com不符合要求
匹配分组
字符 | 功能 |
---|---|
| | 匹配左右任意一个表达式 |
(ab) | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P<name>) | 分组起别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
示例1: |
需求:匹配出0-100之间的数字
import re
ret = re.match('[1-9]?\d$|100', '67') # 匹配数字或者100,这个符号就相当于是or
ret1 = re.match('[1-9]?\d$|100', '100')
print(ret.group()) # 67
print(ret1.group()) # 100
示例2:()
需求:匹配出163、126、qq邮箱
import re
ret = re.match("(\w{4,20})@(163|126|qq)\.com", "test@gmail.com")
if ret:
print(ret.group())
print(ret.group(1)) # 输出前面的4-20位
print(ret.group(2)) # 输出后面的163或者126或者qq
else:
print("不是163、126、qq邮箱") # 不是163、126、qq邮箱
示例3:\
需求:匹配出<html>hh</html>
import re
# 能够完成正确的字符串匹配
ret = re.match('<[a-zA-Z]*>\w*</[a-zA-Z]*>', '<html>hh</html>')
ret1 = re.match('<[a-zA-Z]*>\w*</[a-zA-Z]*>', '<html>hh</htmljvjufvf>')
print(ret.group())
print(ret1.group())
运行结果为:
<html>hh</html>
<html>hh</htmljvjufvf>
分析结果可以看到一般写脚本的话前面和后面是一样的,但是可以看到这种写法有漏洞,如果前面和后面不一样也可以匹配到。
完善后:
import re
# 正确的理解思路是:如果在第一对<>中是什么,按理说在后面的那对<>中应该是什么
# 通过引用分组中匹配到的数据即可,但是要注意是元字符串,即类似r""这种格式
ret = re.match(r'<([a-zA-Z]*)>\w*</\1>', '<html>hh</html>') # 正确输出
ret = re.match(r'<([a-zA-Z]*)>\w*</\1>', '<html>hh</htmlnhjvf>') # 报错
print(ret.group())
print(ret1.group())
示例4:\number
需求:匹配出<html><h1>www.itcast.cn</h1></html>
import re
labels = ["<html><h1>www.itcast.cn</h1></html>", "<html><h1>www.itcast.cn</h2></html>"]
for label in labels:
ret = re.match(r'<(\w*)><(\w*)>.*</\2></\1>', label) # 注意整个
if ret:
print('%s是符合要求的标签'%ret.group())
else:
print('%s不符合要求'%label)
运行结果:
<html><h1>www.itcast.cn</h1></html>是符合要求的标签
<html><h1>www.itcast.cn</h2></html>不符合要求
示例5:(?P<name) (?P=name)
匹配出<html><h1>www.itcast.com</h1></html>
import re
ret = re.match(r'<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>', '<html><h1>www.itcast.com</h1></html>')
print(ret.group()) # 匹配成功
re模块的高级用法(Python中有的)
search
需求:匹配出文章阅读的次数
#coding=utf-8
import re
ret = re.search(r"\d+", "阅读次数为 9999互粉厚度u77787")
ret.group() # 输出为9999
注意:match函数是从头进行匹配,search函数是在字符串中进行匹配,但是只会返回第一个匹配到的数据
findall
需求:统计出Python、C、C++相应文章阅读的次数
import re
ret = re.findall(r'\d+', 'pyhon=9999, c=7890, c++=12345')
print(ret)
运行结果:['9999', '7890', '12345']
sub将匹配到的数据进行替换
需求:将匹配到的阅读次数增加1
方法1:
import re
# 作用是:先到后面的字符串进行匹配,然后将匹配到的地方全部由中间的字符串进行替换,然后输出替换后的全部的字符串
ret = re.sub(r'\d+', '998', 'python=997, c++=126')
print(ret) # 输出结果:python=998, c++=998
方法2:
import re
def add(temp): # temp中放的是匹配到的数据
strNum = temp.group()
num = int(strNum) + 1
return str(num)
# sub函数中也可以放函数的引用,将函数的返回值作为替换后的值
ret = re.sub(r"\d+", add, "python = 997")
print(ret)
ret = re.sub(r"\d+", add, "python = 99")
print(ret)
split根据匹配进行切割字符串,并返回一个列表
需求:切割字符串‘info:xiaozhang 33 shangdong’
#coding=utf-8
import re
ret = re.split(r":| ","info:xiaoZhang 33 shandong")
print(ret)
运行结果:
['info', 'xiaoZhang', '33', 'shandong']
小训练:
需求:从下面的字符串中取出文本
div>
<p>岗位职责:</p>
<p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
<p><br></p>
<p>必备要求:</p>
<p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
<p> <br></p>
<p>技术要求:</p>
<p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
<p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
<p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
<p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
<p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
<p> <br></p>
<p>加分项:</p>
<p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>
</div>
re.sub(r"<[^>]*>| |\n", "", test_str)
贪婪和非贪婪
Python中数量默认的是贪婪的(在少数语言中可能是非贪婪的),总数尝试匹配尽量多的字符;非贪婪相反,总是尝试匹配尽可能少的字符。
在‘*’、‘?’、‘+’、‘{}’后面加上?,使贪婪变为非贪婪。
>>> s="This is a number 234-235-22-423"
>>> r=re.match(".+(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'4-235-22-423'
>>> r=re.match(".+?(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'234-235-22-423'
正则表达式模式中使用的通配字,那它在从左往右的顺序求值时,会尽量抓取满足匹配的最长的字符串,在我们上面的例子中,‘+’会从字符串的起始处尽量抓去满足匹配的最长字符,其中包括我们想得到的第一个整型字段中的大部分,‘\d+’仅分配了一部分进行匹配,所以匹配的数字4
解决方式:非贪婪操作符‘?’,这个操作符可以用在‘*’、‘+’、‘?’的后面,要求正则匹配的越少越好
>>> re.match(r"aa(\d+)","aa2343ddd").group(1)
'2343'
>>> re.match(r"aa(\d+?)","aa2343ddd").group(1)
'2'
>>> re.match(r"aa(\d+)ddd","aa2343ddd").group(1)
'2343'
>>> re.match(r"aa(\d+?)ddd","aa2343ddd").group(1)
'2343'
应用:
在实际的使用的过程中,我们一般先将正则表达式的字符串形式编译为pattern实例,然后再进行匹配操作
使用re的一般步骤是:
- 将正则表达式的字符串形式编译为pattern实例
- 使用pattern实例处理文本并获得匹配结果(一个match实例)
- 使用match实例获得信息,进行其他的操作
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello.*\!')
# 使用Pattern匹配文本,获得匹配结果,无法匹配时返回None
match = pattern.match('hello hanxiaoyang! How are you?')
if match:
# 使用match获得分组信息
print(match.group())
第二个参数flag是匹配模式,取值可以使用按位或运算符‘|’表示同时生效,这个一般来说不会怎么用,需要用的时候再查吧