15.正则表达式
一、 常用语法
. * + ? \ [ ] ^ $ { } | ( )
1. 点 .
--- 匹配所有字符
.
:表示要匹配除了 换行符 之外的 所有 单个
字符 。
content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''
import re
p = re.compile(r'.色')
for one in p.findall(content):
print(one)
执行结果:.色
绿色
橙色
黄色
黑色
2. 星号 *
--- 重复匹配任意次
*
:表示匹配前面的子表达式任意次,包括 0 次
content = '''苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,'''
import re
p = re.compile(r',.*')
for one in p.findall(content):
print(one)
执行结果:,.*
,是绿色的
,是橙色的
,是黄色的
,是黑色的
,
紧跟在
.
后面, 表示 任意字符可以出现任意次, 所以整个表达式的意思就是在逗号后面的 所有字符,包括逗号.*
在正则表达式中非常常见,表示匹配任意字符任意次数。*
前面不是非得是 点 ,也可以是其它字符
3. 加号 +
--- 重复匹配多次
+
:表示匹配前面的子表达式一次或多次,不包括 0 次。
content = '''苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,'''
import re
p = re.compile(r',.+')
for one in p.findall(content):
print(one)
执行结果:,.+
,是绿色的
,是橙色的
,是黄色的
,是黑色的
4. 问号 ?
--- 匹配 0 ~ 1 次
?
:表示匹配前面的子表达式 0 次或 1 次。
content = '''苹果,是绿色的
橙子,橙色的
香蕉,黄色的
乌鸦,黑色的
猴子,'''
import re
p = re.compile(r',.?')
for one in p.findall(content):
print(one)
执行结果:,.?
,绿
,橙
,黄
,黑
,
5. 花括号 {}
--- 匹配指定次数
{}
:表示 前面 的字符匹配 指定的次数
红彤彤,绿油油,黑乎乎,绿油油油油
执行结果:油{3,4}
油{3}
:就表示匹配 连续的 油 字 3 次油{3,4}
:就表示匹配 连续的 油 字 至少 3 次,至多 4 次
6. 贪婪模式 和 非贪婪模式
*
、 +
:在正则表达式中都是 贪婪的 ,他们会尽可能多的去匹配。
非贪婪模式,也就是在星号后面加上 ?
source = '<html><head><title>Title</title>'
import re
# 注意多出的问号
p = re.compile(r'<.*?>')
print(p.findall(source))
执行结果:
['<html>', '<head>', '<title>', '</title>']
7. 对元字符转义
\
:反斜杠配合元字符使用,可以对元字符进行 转义 ,使其成为普通字符
content = '''苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的'''
import re
p = re.compile(r'.*\.')
for one in p.findall(content):
print(one)
执行结果:.*\.
苹果.
橙子.
香蕉.
8. 匹配某种字符类型
\d
:匹配 0-9
之间任意一个数字字符,等价于表达式 [0-9]
\D
:匹配任意一个不是 0-9
之间的数字字符,等价于表达式 [^0-9]
\s
:匹配任意一个空白字符,包括 空格、tab、换行符等,等价于表达式 [\t\n\r\f\v]
\S
:匹配任意一个非空白字符,等价于表达式 [^ \t\n\r\f\v]
\w
:匹配任意一个文字字符,包括大小写字母、数字、下划线,等价于表达式 [a-zA-Z0-9_]
缺省情况也包括 Unicode
文字字符,如果指定 ASCII 码标记,则只包括 ASCII 字母
\W
:匹配任意一个非文字字符,等价于表达式 [^a-zA-Z0-9_]
反斜杠 也可以用在方括号里面,比如 [\s,.]
表示匹配 : 任何空白字符, 或者逗号,或者点
9. 方括号 []
--- 匹配几个字符之一
[]
:表示要匹配 指定的几个字符之一
比如:
[abc]
可以匹配 a, b, 或者 c 里面的任意一个字符。等价于 [a-c]
。
[a-c]
中间的 - 表示一个范围从 a 到 c。
提示
1.元字符
在 []
中 为 普通字符
2.在 []
中使用 ^
表示 非
方括号里面的字符合集。
content = 'a1b2c3d4e5'
import re
p = re.compile(r'[^\d]' )
for one in p.findall(content):
print(one)
执行结果:
a
b
c
d
e
10. 起始、结尾位置 和 单行、多行模式
^
:表示 匹配文本的开始
位置默认为 单行模式 , 多行模式 需要增加参数
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)
执行结果:
001 002 003
去掉 compile 的第二个参数 re.M, 运行结果:
001
- 单行模式 : 表示匹配
$
:表示 匹配文本的结束
位置默认为 单行模式 , 多行模式 需要增加参数
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)
执行结果:
60 70 80
去掉 compile 的第二个参数 re.MULTILINE, 运行结果:
80
- 单行模式 : 表示匹配
11. 竖线 |
--- 匹配其中之一
|
:表示 匹配 其中之一
提示
竖线 在正则表达式的优先级 最低 ,意味着, 竖线隔开的部分是 一个整体。
12. 括号 ()
--- 分组
()
: 表示为 正则表达式的 组选择。
组
:就是把 正则表达式 匹配的内容 其中的某些部分 标记为某个组
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'), match.group('phone'))
执行结果:
张三 15945678901
李四 13945677701
王二 13845666901
13. 让 点 匹配换行
re.DOTALL
参数 :可以使 点也能匹配 换行符
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)
执行结果:
Python开发工程师
java开发工程师
二、 切割字符串
split
方法 :可以切割 不同 分隔符 的字符串
import re
names = '关羽; 张飞, 赵云, 马超, 黄忠 李逵'
namelist = re.split(r'[;,\s]\s*', names)
print(namelist)
执行结果:
['关羽', '张飞', '赵云', '马超', '黄忠', '李逵']
[;,\s]\s*
指定了,分割符为 分号、逗号、空格 里面的任意一种均可,并且 该符号周围可以有不定数量的空格。
三、 字符串替换
1. 匹配模式替换
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)
- 第一个参数
/av\d+?/
这个正则表达式,表示以/av
开头,后面是一串数字,再以/
结尾的 这种特征的字符串 ,是需要被替换的。 - 第二个参数,这里 是
'/cn345677/'
这个字符串,表示用什么来替换。 - 第三个参数是 源字符串。
2.指定替换函数
sub
函数 : 可以使用 函数 替换指定位置的字符串
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):
# Match对象 的 match[0] 返回的是整个匹配上的字符串,
src = match[0]
# Match对象 的 match[1] 返回的是第一个group分组的内容
number = int(match[1]) + 6
dest = f'/av{number}/'
print(f'{src} 替换为 {dest}')
# 返回值就是最终替换的字符串
return dest
newStr = re.sub(r'/av(\d+?)/', subFunc, names)
print(newStr)