正则表达式
语法:用来描述你想搜索的字符串的特征;简单化
正常情况
content = '''
Python3 高级开发工程师 上海互教教育科技有限公司上海-浦东新区2万/月02-18满员
测试开发工程师(C++/python) 上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月02-18未满员
Python3 开发工程师 上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python) 赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师 上海行动教育科技股份有限公司上海-闵行区2.8万/月02-18剩余255人
python开发工程师 上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''
# 将文本内容按行放入列表
lines = content.splitlines()
for line in lines:
# 查找'万/月' 在 字符串中什么地方
pos2 = line.find('万/月')
if pos2 < 0:
# 没找到就找'万/每月' 在 字符串中什么地方
pos2 = line.find('万/每月')
# 都找不到
if pos2 < 0:
continue
# 执行到这里,说明可以找到薪资关键字
# 接下来分析 薪资 数字的起始位置
# 方法是 找到 pos2 前面薪资数字开始的位置
idx = pos2-1
# 只要是数字或者小数点,就继续往前面找
while line[idx].isdigit() or line[idx]=='.':
idx -= 1
# 现在 idx 指向 薪资数字前面的那个字,
# 所以薪资开始的 索引 就是 idx+1
pos1 = idx + 1
print(line[pos1:pos2])
使用正则表达式
content = '''
Python3 高级开发工程师 上海互教教育科技有限公司上海-浦东新区2万/月02-18满员
测试开发工程师(C++/python) 上海墨鹍数码科技有限公司上海-浦东新区2.5万/每月02-18未满员
Python3 开发工程师 上海德拓信息技术股份有限公司上海-徐汇区1.3万/每月02-18剩余11人
测试开发工程师(Python) 赫里普(上海)信息科技有限公司上海-浦东新区1.1万/每月02-18剩余5人
Python高级开发工程师 上海行动教育科技股份有限公司上海-闵行区2.8万/月02-18剩余255人
python开发工程师 上海优似腾软件开发有限公司上海-浦东新区2.5万/每月02-18满员
'''
import re
for one in re.findall(r'([\d.]+)万/每{0,1}月', content):
print(one)
常见语法
普通字符&汉字直接匹配;特殊字符就有特殊含义
如:. * + ? \ [ ] ^ $ { } | ( )
点
. 表示匹配除了 换行符
之外的任何 单个
字符
当匹配规则只使用一次用 re.findall
content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''
import re
for one in re.findall('.色',content):
print(one)
否则用re.compile
产生的正则表达式对象
content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''
import re
p = re.compile('.色')
for one in p.findall(content):
print(one)
星号
*
表示匹配前面的子表达式任意次,包括0次
例如:abc*de:表示 ab 和 de 之间有任意个数(包括0)c 。
特:".* ":表示匹配一串任意长度的字符串任意次。这个时候必须在“.*”的前后加其他的符号来限定范围,否则得到的结果就是原来的整个字符串
例如:
content = '''苹果,是绿色的 橙子,是橙色的 香蕉,是黄色的 乌鸦,是黑色的 猴子,''' import re p = re.compile(r',.*') for one in p.findall(content): print(one)
加号
+ 表示匹配前面的子表达式一次或多次,不包括0次(至少出现1次)
例如:a+b
可以匹配"ab"、“aab”、“aaab"等,但不会匹配单独的"b”
特:".+ ":与.*不同的是,不包括0次,逗号后没内容的就不选
例如:
content = '''苹果,是绿色的 橙子,是橙色的 香蕉,是黄色的 乌鸦,是黑色的 猴子,''' import re p = re.compile(r',.+') for one in p.findall(content): print(one)
问号
?
表示匹配前面的子表达式0次或1次
例如:a?b
可以匹配"b"或者"ab"
花括号
{}表示 前面的字符匹配 指定的次数
例如:油{3}
就表示匹配 连续的 油 字 3次;油{3,4}
就表示匹配 连续的 油 字 至少3次,至多 4 次
一个问题:r''
r''是为了防止字符被转义,也就是原生字符串
''这个形式,字符串里含有\n的话就会被转义成换行符;不想被转义的话就在前加\(r"用的就是这个原理)
>>> s='abc\nabc' >>> s 'abc\nabc' >>> print s abc abc >>> s=r'abc\nabc' >>> s 'abc\\nabc' >>> print s abc\nabc
贪婪模式改非贪婪模式
在正则表达式中 "*"、 "+"、"?"都是贪婪的;会尽可能多的匹配内容
什么意思,举个例子:<html><head><title>Title</title> 我要提取这个字符串的所有Html标签
但要这样写 re.compile(r'<.*>').findall('<html><head><title>Title</title>')
结果是<html><head><title>Title</title> 它是<html><head><title>Title</title>匹配的最后一个>
改成非贪婪模式需要在*后面加?也就是 re.compile(r'<.*?>').findall('<html><head><title>Title</title>')
>>>['<html>', '<head>', '<title>', '</title>']
对元字符的转义
待搜索的文本:
苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的
想要的内容:
苹果.
橙子.
香蕉.
这时如果正则表达式写成re.compile(r'.*.').findall(content)不对;因为.点是一个元字符,直接出现在正则表达式中,表示匹配任意的单个字符, 不能表示 . 这个字符本身的意思了,那就得加个\进行转义 re.compile(r'.*\.').findall(content)
匹配某种字符类型
\d:匹配0-9之间任意一个数字字符
\D:匹配任意一个非0-9数字的字符
\s:匹配任意一个空白字符,包括 空格、tab、换行符等
\S:匹配任意一个非空白字符
\w:匹配任意一个文字字符,包括大小写字母、数字、下划线
\W:匹配任意一个非文字字符
方括号
匹配指定的几个字符之一
例如:[abc] 匹配 a, b, 或者 c 里面的任意一个字符 ; <=> [a-c]
注意:一些元字符比如点在[]中和普通字符一样;但^在[]表非的含义
起始、结尾位置和单行、多行模式
^ 表示匹配文本的开头位置
正则表达式通过compile的第二个参数re.M 来指明使用的是多行模式
单行模式:匹配
整个文本
的开头位置多行模式:匹配
文本每行
的开头位置
例如:在下面文本内容提取编号
content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''
import re
p = re.compile(r'^\d+', re.M)
for one in p.findall(content):
print(one)
r'^\d+' :匹配文本每行开头位置,0-9,匹配前面子表达式至少出现1次
去掉re.M的话是单行模式,^ 只会匹配整个文本的开头位置 >>> 001
$表示匹配文本的结尾位置
正则表达式通过compile 的第二个参数 re.MULTILINE ,指明了使用的是多行模式
单行模式:匹配
整个文本
的开头位置多行模式:匹配
文本每行
的开头位置
例如:在下面文本内容提取价格
content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''
import re
p = re.compile(r'\d+$', re.MULTILINE)
for one in p.findall(content):
print(one)
去掉 re.MULTILINE的话就是单行模式,$ 只会匹配整个文本的结束位置 >>>80
竖线
匹配其中之一
竖线在正则表达式的优先级最低
括号
例1
待搜索文本:
苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的
想要的内容:
苹果
橙子
香蕉
content = '''苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的'''
import re
p = re.compile(r'^(.*),', re.MULTILINE)
for one in p.findall(content):
print(one)
例2
待搜索文本:
张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901
content = '''张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901'''
import re
p = re.compile(r'^(.+),.+(\d{11})', re.MULTILINE)
for one in p.findall(content):
print(one)
>>> ('张三', '15945678901')
('李四', '13945677701')
('王二', '13845666901')
当有多个分组时,可以使用 (?P<分组名>...)
这样的格式,给每个分组命名,以便后续的代码提取每个分组里面的内容
content = '''张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901'''
import re
p = re.compile(r'^(?P<name>.+),.+(?P<phone>\d{11})', re.MULTILINE)
for match in p.finditer(content):
print(match.group('name'))
print(match.group('phone'))
张三
15945678901
李四
13945677701
王二
13845666901
让点匹配换行
content = '''
<div class="el">
<p class="t1">
<span>
<a>Python开发工程师</a>
</span>
</p>
<span class="t2">南京</span>
<span class="t3">1.5-2万/月</span>
</div>
<div class="el">
<p class="t1">
<span>
<a>java开发工程师</a>
</span>
</p>
<span class="t2">苏州</span>
<span class="t3">1.5-2/月</span>
</div>
'''
import re
p = re.compile(r'class="t1">.*?<a>(.*?)</a>', re.DOTALL)
for one in p.findall(content):
print(one)
正常情况下点是不匹配换行符的;要想匹配换行符需要在compile函数的第二个参数设成re.DOTALL
正则表达式中的所有函数
search
扫描整个字符串,判断有无匹配的子串,如果匹配成功,将返回第一个匹配的字符串对象
import re
text = "Hello, world! How are you?"
pattern = "world"
match = re.search(pattern, text)
if match:
print(match)
else:
print("匹配失败")
>>> <re.Match object; span=(7, 12), match='world'>
match
用于判断字符串的起始位置是否与正则表达式匹配
它接受两个参数:第一个是正则表达式模式,第二个是要与该模式匹配的字符串。
如果匹配成功,它会返回一个匹配对象,如果匹配失败,则返回 None
import re
text = "Hello, world!"
pattern = re.compile("Hello")
match = pattern.match(text)
if match:
print(match)
else:
print("匹配失败")
>>> <re.Match object; span=(0, 5), match='Hello'>
findall
会找到所有的匹配结果,并且将所有的匹配结果组成一个列表进行返回
import re
text = "Hello, world! How are you? world"
pattern = "world"
match = re.findall(pattern, text)
if match:
print(match)
else:
print("匹配失败")
>>> ['world', 'world']
fullmatch
用于检查输入字符串是否完全匹配给定的正则表达式模式
它接受两个参数:第一个是正则表达式模式,第二个是要与该模式匹配的字符串。
如果匹配成功,它会返回一个匹配对象,如果匹配失败,则返回 None
import re
text = "Hello, world!"
pattern = re.compile("Hello, world!")
match = pattern.fullmatch(text)
if match:
print(match)
else:
print("整个字符串与模式不匹配。")
>>> <re.Match object; span=(0, 13), match='Hello, world!'>
表示在[0-13)之间匹配到了字符串Hello, world!
span表示的是匹配上的字符串的开始位置与结束位置,match表示匹配上的内容
finditer
寻找字符串中与正则表达式匹配的字符串片段的所有结果;与findall()函数不同的是,finditer()函数返回的是一个迭代器,并可以获取更多的信息,如匹配字符串的起始和终止位置。
import re
text = "Hello, world! How are you? world"
pattern = "world"
match = re.finditer(pattern, text)
if match:
print(match)
else:
print("匹配失败")
>>> <callable_iterator object at 0x000002CD5220F9A0>
print([i for i in match])
[<re.Match object; span=(7, 12), match='world'>, <re.Match object; span=(27, 32), match='world'>]
对比findall()
import re text = "Hello, world! How are you? world" pattern = "world" match = re.findall(pattern, text) if match: print(match) else: print("匹配失败")
['world', 'world']
split
用于在字符串中按照指定的规则分割字符串
该函数接受两个参数:第一个是要分割的字符串,第二个是分割规则(正则表达式)
它返回一个字符串列表,每个字符串代表一个分割后的部分
import re
re_str = r'\d+'
str1 = 'qwer1tyui345osdfghj99876kl'
result = re.split(re_str,str1)
print(result)
>>> ['qwer', 'tyui', 'osdfghj', 'kl']
这里 r'\d+' 表示至少1个或多个数字
sub
用于在字符串中替换与指定正则表达式匹配的部分
该函数接受三个参数:第一个是替换规则(正则表达式),第二个是要替换的字符串,第三个是要被替换的字符串。
它返回一个替换后的字符串
import re
re_str = r'\d+'
str1 = 'qwer1tyui345osdfghj99876kl'
str1 = re.sub(re_str, '一二三',str1) # 用'一二三'替换str1中所有匹配re_str的子串
print(str1)
>>> qwer一二三tyui一二三osdfghj一二三kl
compile
将正则表达式字符串编译成一个正则表达式对象
import re
re_pattern = re.compile(r'\d+')
str1 = 'qwer1tyui345osdfghj99876kl'
result1 = re_pattern.findall(str1)
result2 = re_pattern.search(str1)
print(result1)
print(result2)
>>> ['1', '345', '99876']
<re.Match object; span=(4, 5), match='1'>
切割字符串
import re
names = '关羽; 张飞, 赵云, 马超, 黄忠 李逵'
namelist = re.split(r'[;,\s]\s*', names)
print(namelist)
r'[;,\s]\s*':代表从;,空格任选其一,并且该符号周围可以有不定数量的空格
字符串替换
匹配模式替换
import re
names = '''
下面是这学期要学习的课程:
<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律
<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式
<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''
newStr = re.sub(r'/av\d+/', '/cn345677/' , names)
print(newStr)
指定模式替换
要求:替换后的内容 是原来的数字+6, 比如 /av66771949/
替换为 /av66771955/
import re
names = '''
下面是这学期要学习的课程:
<a href='https://www.bilibili.com/video/av66771949/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律
<a href='https://www.bilibili.com/video/av46349552/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式
<a href='https://www.bilibili.com/video/av90571967/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
'''
# 替换函数,参数是 Match对象
def subFunc(match):
print(match)
print(match.group(0))
print(match.group(1))
print(match.groups())
# Match对象 的 group(0) 返回的是整个匹配上的字符串,
src = match.group(0)
# Match对象 的 group(1) 返回的是第一个group分组的内容
number = int(match.group(1)) + 6
dest = f'/av{number}/'
print(f'{src} 替换为 {dest}')
# 返回值就是最终替换的字符串
return dest
newStr = re.sub(r'/av(\d+)/', subFunc , names)
print(newStr)
<re.Match object; span=(56, 68), match='/av66771949/'>
/av66771949/
66771949
('66771949',)
/av66771949/ 替换为 /av66771955/
<re.Match object; span=(168, 180), match='/av46349552/'>
/av46349552/
46349552
('46349552',)
/av46349552/ 替换为 /av46349558/
<re.Match object; span=(281, 293), match='/av90571967/'>
/av90571967/
90571967
('90571967',)
/av90571967/ 替换为 /av90571973/
下面是这学期要学习的课程:<a href='https://www.bilibili.com/video/av66771955/?p=1' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是牛顿第2运动定律<a href='https://www.bilibili.com/video/av46349558/?p=125' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是毕达哥拉斯公式<a href='https://www.bilibili.com/video/av90571973/?p=33' target='_blank'>点击这里,边看视频讲解,边学习以下内容</a>
这节讲的是切割磁力线
match.group() & match.groups()
首先在正则表达式中 ()定义了一个组;这里(\d+)是一组
match.group(0) :匹配的是整个结果
match.group(1):匹配的是第一个group值
这里是('66771949',)的66771949
注意:
为什么match.group(2)会报错 —— 当元组中只有一个元素,必须在它后面加逗号;这个元组只有一个group值
match.groups():返回所有的group,以元组的形式
参考自:python正则表达式中group_match.group()-CSDN博客
原文地址:https://blog.csdn.net/m0_73557953/article/details/142922197
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!