Python正则表达式的re模块、零宽断言、分组向后引用

目录

1、前言

1.1  什么是正则表达式

1.2  正则的目的

1.3  正则表达式的优缺点

1.4  符号

2、re模块的基本用法

2.1  match与search  查找第一个匹配

2.1.1  re.search

2.1.2  re.match 

2.1.3  注意

2.2  findall 和 finditer  找到多个匹配

2.2.1  re.findall

2.2.2  re.finditer

2.2.3  区别  

2.3 re.sub('匹配正则' , '替换内容' , 'string')

2.4  编译正则:re.compile('匹配正则')

        2.4.1  编译正则的特点

3、基本正则匹配

3.1  基本正则匹配-区间

3.2  基本正则匹配-或匹配

3.3  基本正则匹配-取反

4、正则重复

4.1  贪婪模式和非贪婪模式

5、  正则分组

5.1  简单分组

5.2  分组向后引用(引用分组)

5.3  命名分组

5.4  捕获分组和非捕获分组

6、正则标记

 6.1 内联标记: (?imx)re

 6.2  内联标记:(?imx: re)

 6.3  举例

7、正则断言

7.1  定义

7.2  举例

8、习题

8.1  找出IP地址

8.2


1、前言

1.1  什么是正则表达式

        正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。

1.2  正则的目的

  • 数据挖掘
  • 验证
  • 指定一个匹配规则,从而识别该规则是否在一个更大的文本字符串中
  • 正则表达式可以识别匹配规则的文本是否存在
  • 还能将一个规则分解为一个或多个子规则,并展示每个子规则匹配的文本

1.3  正则表达式的优缺点

  • 优点:提高工作效率、节省代码
  • 缺点:复杂,难于理解

        官方文档:re — Regular expression operations — Python 3.10.6 documentation

1.4  符号

  • ?                 匹配前一项0次或一次
  • .                  匹配任意一个除换行符以外的字符,占位符
  • +                 匹配前一项一次以上 1~n次
  • *                 匹配前一项任意次  0~n次
  • {n,m}          匹配前一项n~m次
  • {n,}             匹配前一项n次以上
  • {,m}            匹配前一项0~m次
  • {n}              匹配前一项n次
  • ^                 开头
  • $                 结尾

  • \Axx  匹配以xx字符串开始
  • \b      匹配词边界(字母数字中文都属于单词字符)
  • \B      匹配非词边界
  • \w      匹配单词字符
  • \W     匹配非单词字符
  • \d      匹配数字
  • \D     匹配非数字
  • \s      匹配空白
  • \S     匹配非空白

2、re模块的基本用法

2.1  match与search  查找第一个匹配

2.1.1  re.search

        查找匹配项,接受一个正则表达式和字符串,并返回发现的第一个匹配。如果完全没有找到匹配,re.search返回None。

import  re
rest = re.search(r"san","hello san")
print(rest)

输出:
<re.Match object; span=(6, 9), match='san'>

2.1.2  re.match 

        从字符串头查找匹配项,接受一个正则表达式和字符串,从主串第一个字符开始匹配,并返回发现的第一个匹配。如果字符串开始不符合正则表达式,则匹配失败,re.match返回None。

        match.group(default=0):返回匹配的字符串。

        group是由于正则表达式可以分拆为多个只调出匹配子集的子组,0是默认参数,表示匹配的整个串,n 表示第n个分。

        match.start():

        start方法提供了原始字符串中匹配开始的索引。

        match.end():

        end方法提供了原始字符串中匹配开始的索引。

        match.groups():

        groups返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

import  re
rest = re.match(r"san","hello san")
print(rest)

输出:
None

         r'san' 中的r代表的是raw(原始字符串),原始字符串与正常字符串的区别是原始字符串不会将\字符解释成一个转义字符,正则表达式使用原始字符很常见且有用。

2.1.3  注意

        re.match()函数只检测RE是不是在string的开始位置匹配,也就是说match()只有在0位置匹配成功的话才有返回, 如果不是开始位置匹配成功的话,match()就返回none, 不能和span()、group()搭配使用,否则会报错。以下的写法是错误的。

        search()会扫描整个string查找匹配;search()可以不从0位置开始匹配,这就是和match()的区别。

        参考文章:正则表达式match()与search()的区别_Jerry_JD的博客-CSDN博客

2.2  findall 和 finditer  找到多个匹配

2.2.1  re.findall

        查找并返回匹配的字符串,返回一个列表。

import  re
rest = re.findall(r"a","It's raining cats and dogs")
print(rest)

输出:
['a', 'a', 'a']

2.2.2  re.finditer

        查找并返回匹配的字符串,返回一个迭代器。

import  re
rest = re.finditer(r"a","It's raining cats and dogs")
print(rest)

输出:
<callable_iterator object at 0x000002D32C74AF10>

2.2.3  区别  

  •         findall 找到所有匹配内容,放到一个列表里返回。
  •         finditer 找到所有匹配内容,返回一个迭代器,惰性求值。
  •         finditer 找到每个内容都是一个match对象,需要group来获取里面具体的匹配字符串。
  •         findall 直接返回匹配上的字符串。

2.3 re.sub('匹配正则' , '替换内容' , 'string')

        将string中匹配的内容替换为新内容。

import re
srt1 = "hello, i am learnng python python"
print(re.sub("p.{2}","xixi",srt1))

输出:
hello, i am learnng xixihon xixihon

2.4  编译正则:re.compile('匹配正则')

        2.4.1  编译正则的特点

        • 复杂的正则可复用。

        • 使用编译正则更方便,省略了参数。

        • re模块缓存它即席编译的正则表达式,因此在大多数情况下,使用compile并没有很大 的性能优势

m = "my name is jack"
m1 = "my name is rose"

reg = re.compile("is\s(.*)$")
print(reg.findall(m))
print(reg.findall(m1))

输出:
['jack']
['rose']

3、基本正则匹配

3.1  基本正则匹配-区间

        最简单的正则表达式是那些仅包含简单的字母数字字符的表达式,复杂的正则可以实现强大的匹配。

         区间:[]

        正则匹配区分大小写。

import re
ret = re.findall("[12pP]x","2px 1xx Pytho pxoo python2 121Px")
print(ret)
ret1 = re.findall("[a-zA-Z0-9]","dafdasf3224redfr54ewqPOJN")
print(ret1)

输出:
['px', '1x', 'px', 'Px']
['d', 'a', 'f', 'd', 'a', 's', 'f', '3', '2', '2', '4', 'r', 'e', 'd', 'f', 'r', '5', '4', 'e', 'w', 'q', 'P', 'O', 'J', 'N']

3.2  基本正则匹配-或匹配

        匹配a或b:a|b。

import re
ret = "sddafds fvguu"
r = re.search("s|u",ret)
print(r.group())

输出:
s

3.3  基本正则匹配-取反

        取反:[^abc]

        匹配a+非小写字母。

ret = "sddafds fvguu 123"
re1 = re.findall(r"[^A-z]",ret)
print(re1)

输出:
[' ', ' ', '1', '2', '3']

4、正则重复

4.1  贪婪模式和非贪婪模式

        贪婪模式(.*):尽可能的匹配长的字符串

        非贪婪模式(.*?)尽可能的匹配短的字符串(只要在可能出现贪婪的地方加个 ?:+?、*?、{,4}?)

ret = re.findall("py*?","pyhhhheewipyyyyyyyyyyy")
print(ret)

输出:
['p', 'p']


ret = re.findall("py*","pyhhhheewipyyyyyyyyyyy")
print(ret)

输出:
['py', 'pyyyyyyyyyyy']

5、  正则分组

5.1  简单分组

        当使用分组时,除了可以获得整个匹配,还能够获得选择每一个单独组,使用 () 进行分组。

import re
m = "tel:1577-379-3551-55"
ret = re.search(r'(\d{4})-(\d{3})-(\d{4})-(\d{2})',m)
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))
print(ret.group(4))

输出:
1577-379-3551-55
1577
379
3551
55

5.2  分组向后引用(引用分组)

        使用()分用,用\0, \1, \2引用 (\0表示匹配的整个串)。

 

        'NoneType' object 得到的结果为空(没有返回,NoneType是一个特殊类型,里面只有一个值None)。

5.3  命名分组

        命名分组:(?P规则)

import re
# # 命名分组
m = "tel:1577-379-3551-55"
ret = re.search(r'(?P<first>\d{4})-(\d{3})-(\d{4})', m)
print(ret.group())
print(ret.group("first"))
print(ret.groupdict())

输出:
1577-379-3551
1577
{'first': '1577'}

5.4  捕获分组和非捕获分组

        捕获分组:

        分组之后分配到的数据会放在内存里面,并且给定一个从1开始的索引,捕获分组是可以进行分组向后引用的。

        非捕获分组(?:正则表达式):

        只分组不捕获,匹配到的分组数据不存放在内存里,不可以进行分组向后引用的

6、正则标记

内联标记:

修饰符功能
(?imx)正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?imx: re)在括号中使用i, m, 或 x 可选标志

6.1 内联标记: (?imx)re

 

 6.2  内联标记:(?imx: re)

 6.3  举例

msg = """you jump, i jump
YOU JUMP, I JUMP"""
# # 对大小写不敏感
# # ret = re.findall(r"jump",msg,re.I)
#
# # 多行模式,影响开始和结束
# ret = re.findall(r"^you jump, i jump$",msg,re.I|re.M)
# print(ret)

# re.S 让.匹配任意字符
ret = re.findall(r"^you.*jump$", msg, re.I|re.S)
print(ret)

7、正则断言

7.1  定义

        正则表达式的断言分为:先行断言(lookahead)和后行断言(lookbehind) 正则表达式的先行断言和后行断言一共有4种形式:

  • (?=pattern) 零宽正向先行断言(zero-width positive lookahead assertion)
  • (?!pattern) 零宽负向先行断言(zero-width negative lookahead assertion)
  • (?<=pattern) 零宽正向后行断言(zero-width positive lookbehind assertion)
  • (?<!pattern) 零宽负向后行断言(zero-width negative lookbehind assertion)

        零宽正向先行断言:(?=pattern)

• 代表字符串中的一个位置,紧接该位置之后的字符序列能够匹配pattern。

• 匹配字符串re,后面能接gular(但不匹配宽度)

        零宽负向先行断言:(?!pattern)

• 代表字符串中的一个位置,紧接该位置之后的字符序列不能匹配pattern。

• 匹配字符串re,但是后面不能接gular

        零宽正向后行断言:(?<=pattern)

• 代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配pattern。

• 匹配gular,但前面必须是re

7.2  举例

import re
# 零宽断言  不占用匹配宽度 确定位置
str1 = "红鲤鱼与绿鲤鱼与驴"
print(re.findall(r".鲤鱼(?=与驴)",str1))#找后面是与驴的鲤鱼
print(re.findall(r".鲤鱼(?!与驴)",str1))#找后面不是与驴的鲤鱼
print(re.findall(r"(?<=红)鲤鱼..",str1))
print(re.findall(r"(?<!红)鲤鱼..",str1))

输出:
['绿鲤鱼']
['红鲤鱼']
['鲤鱼与绿']
['鲤鱼与驴']

8、习题

8.1  找出IP地址

import re
mga = """
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:a2:f8:96 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.103/24 brd 192.168.0.255 scope global dynamic noprefixroute ens33
       valid_lft 86382sec preferred_lft 86382sec
    inet6 fe80::5a57:c3e5:6e36:230/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
"""
print(re.findall(r"(?<=inet).*(?=brd)",mga))
print(re.findall(r"(?<=ens33).*(?=ens33)",mga, re.I|re.S))

输出:
[' 192.168.0.103/24 ']
[': <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000\n    link/ether 00:0c:29:a2:f8:96 brd ff:ff:ff:ff:ff:ff\n    inet 192.168.0.103/24 brd 192.168.0.255 scope global dynamic noprefixroute ']

8.2

# # 2.验证邮箱地址,126.com、QQ.com、163.com
com = input("请输入你要验证的邮箱:")
if re.findall(r"\w+@(qq|126|163)[.]{1}com$",com):
    print("正确!")
else:
    print("没有这个邮箱~")

# 3.
msg = "comy@xx.comcom123@qq.comaaa@126.combbb@163.comcc@abc.com"
print(re.findall(r"(?:\.com)?(\w+@(?:qq|126|163).com)",msg))
# print(ret3.group(1))

ret4 = ".com".strip()
print(ret4)



输出:
请输入你要验证的邮箱:2378996584@qq.com
正确!
['com123@qq.com', 'aaa@126.com', 'bbb@163.com']
.com

资源下载链接为:https://pan.quark.cn/s/27aaeeaf622d在当今数字化时代,智能停车系统已成为城市交通管理的重要组成部分。本文将详细剖析一款基于SpringBoot框架开发的停车场管理系统。该系统融合了百度地图和支付宝沙箱支付等前沿技术,致力于提升停车服务的效率与便捷性。SpringBoot是领域Java广受欢迎的微服务框架,以其简洁配置、快速启动和自动配置功能备受青睐。在该停车场管理系统中,SpringBoot作为核心架构,负责应用程序的运行与管理,为系统提供了高效、稳定的运行基础。MySQL作为系统的数据库管理系统,用于存储车辆进出记录、用户信息、收费明细等关键数据。通过精心设计的数据库表结构和高效的SQL查询,系统能够快速处理和检索大量实时数据,确保稳定运行。Thymeleaf是SpringBoot中常用的模板引擎,用于动态生成HTML页面。它在顾客端页面和后台管理员页面的交互设计中发挥了重要作用,提供了简洁的语法,帮助开发者快速构建响应式用户界面,从而提升用户体验。此外,系统还集成了百度地图API,增加了地理定位功能。用户可以通过地图直观查看停车场位置,并获取导航服务。同时,系统利用百度地图API实时获取车位信息,帮助用户规划最优停车路线。支付宝沙箱支付是该系统的一大特色。它模拟真实交易环境,用于测试和支付验证流程的准确性。在停车场管理系统中,顾客可以通过支付宝沙箱进行安全、便捷的线上支付,简化了支付流程,提升了服务品质。系统的源码部分涵盖了完整的编程代码,包括SpringBoot的配置、控制器、服务层、持久层,以及前端界面的HTML、CSS和JavaScript等。通过学习和分析源码,开发者可以深入了解系统的架构设计和实现细节,为后续的定制和优化提供重要参考。数据库脚本是初始化数据库结构和填充测试数据的关键文件。这些SQL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值