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
e10. 起始、结尾位置 和 单行、多行模式
- ^:表示 匹配文本的- 开始位置
- 默认为 单行模式 , 多行模式 需要增加参数 - 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
王二 1384566690113. 让 点 匹配换行
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)