python正则表达式笔记
常见语法


content = '''苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的'''
import re
p = re.compile(r'.色')
for one in p.findall(content):
print(one)
运行结果如下

字符串前+r表示对字符串不进行任何python字符的转义
compile把正则表达式字符串处理为pattern的对象,可对他进行各种处理
![]()
content = '''苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,'''
import re
p = re.compile(r',.*')
for one in p.findall(content):
print(one)
运行结果如下
,是绿色的
,是橙色的
,是黄色的
,是黑色的
,
注意, .* 在正则表达式中非常常见,表示匹配任意字符任意次数。
当然这个 * 前面不是非得是 点 ,也可以是其它字符,比如





source = '<html><head><title>Title</title>'
import re p = re.compile(r'<.*>')
print(p.findall(source))
结果如下

在正则表达式中, ‘*’, ‘+’, ‘?’ 都是贪婪地,使用他们时,会尽可能多的匹配内容,
所以, <.*> 中的 星号(表示任意次数的重复),一直匹配到了 字符串最后的 </title> 里面的e。
解决这个问题,就需要使用非贪婪模式,也就是在星号后面加上 ? ,变成这样 <.*?>
代码改为
source = '<html><head><title>Title</title>'
import re
# 注意多出的问号
p = re.compile(r'<.*?>')
print(p.findall(source))
结果如下


content = '''苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的'''
import re
p = re.compile(r'.*\.')
for one in p.findall(content):
print(one)
运行结果如下
匹配某种字符类型
反斜杠后面接一些字符,表示匹配 某种类型 的一个字符。
比如
\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,.] 表示匹配 : 任何空白字符, 或者逗号,或者点。
import re
p = re.compile(r'.w{2,4}'re.A)
re.A表示只要英文字符
![]()
content = 'a1b2c3d4e5'
import re
p = re.compile(r'[^\d]' )
for one in p.findall(content):
print(one)

content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''
import re
p = re.compile(r'^\d+', re.M)
for one in p.findall(content):
print(one)
注意,compile 的第二个参数 re.M ,指明了使用多行模式,multline
结果


content = '''001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80'''
import re
p = re.compile(r'\d+$', re.MULTILINE)
for one in p.findall(content):
print(one)
注意,compile 的第二个参数 re.MULTILINE ,指明了使用多行模式,


括号-分组
括号称之为 正则表达式的 组选择。
组 就是把 正则表达式 匹配的内容 里面 其中的某些部分 标记为某个组。
我们可以在 正则表达式中 标记 多个 组
为什么要有组的概念呢?因为我们往往需要提取已经匹配的 内容里面的 某些部分的信心。
前面,我们有个例子,从下面的文本中,选择每行逗号前面的字符串,也 包括逗号本身 。
苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的
就可以这样写正则表达式 ^.*, 。
但是,如果我们要求 不要包括逗号 呢?
当然不能直接 这样写 ^.*
因为最后的逗号 是 特征 所在, 如果去掉它,就没法找 逗号前面的了。
但是把逗号放在正则表达式中,又会包含逗号。
解决问题的方法就是使用 组选择符 : 括号。
我们这样写 ^(.*), ,结果如下

大家可以发现,我们把要从整个表达式中提取的部分放在括号中,这样 水果 的名字 就被单独的放在 组 group 中了。
对应的Python代码如下
content = '''苹果,苹果是绿色的
橙子,橙子是橙色的
香蕉,香蕉是黄色的'''
import re
p = re.compile(r'^(.*),', re.MULTILINE)
for one in p.findall(content):
print(one)
分组 还可以多次使用。
比如,我们要从下面的文本中,提取出每个人的 名字 和对应的 手机号
可以写出如下的代码
content = '''张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901'''
import re
p = re.compile(r'^(.+),.+(\d{11})', re.MULTILINE)
for one in p.findall(content):
print(one)
当有多个分组的时候,我们可以使用 (?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'))
让点匹配换行
前面说过, 点 是 不匹配换行符 的,可是有时候,特征 字符串就是跨行的,比如要找出下面文字中所有的职位名称
<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>
如果你直接使用表达式 class=\"t1\">.*?<a>(.*?)</a> 会发现匹配不上,因为 t1 和 <a> 之间有两个空行。
这时你需要 点也匹配换行符 ,可以使用 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)


import re
names = '关羽; 张飞, 赵云, 马超, 黄忠 李逵'
namelist = re.split(r'[;,\s]\s*', names)
print(namelist)
正则表达式 [;,\s]\s* 指定了,分割符为 分号、逗号、空格 里面的任意一种均可,并且 该符号周围可以有不定数量的空格。
字符串替换
匹配模式替换
字符串 对象的 replace 方法只适应于 简单的 替换。 有时,你需要更加灵活的字符串替换。
比如,我们需要在下面这段文本中 所有的 链接中 找到所以 /avxxxxxx/ 这种 以 /av 开头,后面接一串数字, 这种模式的字符串。
然后,这些字符串全部 替换为 /cn345677/ 。
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>
这节讲的是切割磁力线
'''
被替换的内容不是固定的,所以没法用 字符串的replace方法。
这时,可以使用正则表达式里面的 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>
这节讲的是切割磁力线
'''
newStr = re.sub(r'/av\d+?/', '/cn345677/' , names)
print(newStr)
sub 方法就是也是替换 字符串, 但是被替换的内容 用 正则表达式来表示 符合特征的所有字符串。
比如,这里就是第一个参数 /av\d+?/ 这个正则表达式,表示以 /av 开头,后面是一串数字,再以 / 结尾的 这种特征的字符串 ,是需要被替换的。
第二个参数,这里 是 '/cn345677/' 这个字符串,表示用什么来替换。
第三个参数是 源字符串。
指定替换函数
刚才的例子中,我们用来替换的是一个固定的字符串 /cn345677/。
如果,我们要求,替换后的内容 的是原来的数字+6, 比如 /av66771949/ 替换为 /av66771955/ 。
怎么办?
这种更加复杂的替换,我们可以把 sub的第2个参数 指定为一个函数 ,该函数的返回值,就是用来替换的字符串。
如下
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对象 的 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)
获取组内字符串,如下
match.group(0) # 获取整个匹配字符串
match.group(1) # 获取第1个组内字符串
match.group(2) # 获取第2个组内字符串
Python 3.6 以后的版本 ,写法也可以更加简洁,直接像列表一样使用下标,如下
match[0]
match[1]
match[2]
上面这个例子中:
正则表达式 re.sub 函数执行时, 每发现一个 匹配的子串, 就会:
-
实例化一个 match对象
这个match 对象包含了这次匹配的信息, 比如:整个字符串是什么,匹配部分字符串是什么,里面的各个group分组 字符串是什么
-
调用执行 sub函数的第2个参数对象,也就是调用回调函数subFunc
并且把刚才产生的 match 对象作为参数传递给 subFunc
7.11 不区分大小写的匹配

>>> robocop = re.compile(r'robocop', re.I)
>>> robocop.search('RoboCop is part man, part machine, all cop.').group() 'RoboCop'
>>> robocop.search('ROBOCOP protects the innocent.').group() 'ROBOCOP'
>>> robocop.search('Al, why does your programming book talk about robocop so much?').group() 'robocop'
7.12 用 sub()方法替换字符串
Python来进行查询和替换一个文本字符串?
可以使用sub()方法来进行查询和替换,sub方法的格式为:sub(replacement, string[, count=0])
replacement是被替换成的文本
string是需要被替换的文本
count是一个可选参数,指最大被替换的数量

7.13 管理复杂的正则表达式

7.14 组合使用 re.IGNOREC ASE、re.DOTALL 和 re.VERBOSE





浙公网安备 33010602011771号