Skip to content

正则表达式

正则表达式

5.1 正则表达式概述

一、为什么要学习正则表达式

在实际开发过程中经常会有查找符合某些复杂规则的字符串的需要

比如:邮箱、手机号码、图片地址等

这时候想匹配或者查找符合某些规则的字符串就可以使用==正则表达式==了

二、什么是正则表达式

正则表达式(regular expression)是一种用于匹配字符串中字符组合的==模式==。它由普通字符和特殊字符(元字符)组成,形成了一种强大的文本处理工具。

模式:一种特定的字符串模式,这个模式是通过一些特殊的符号组成的。

正则表达式的特点

​ 正则表达式的语法很令人头疼,可读性差

​ 正则表达式通用行很强,能够适用于很多编程语言

0\d{2}-\d{8} 这个就是一个正则表达式,表达的意思是匹配的是座机号码

正则表达式并不是Python所特有的,在Java、PHP、Go以及JavaScript等语言中都是支持正则表达式的。

三、正则表达式的功能

正则表达式可以用来检查一个大串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

① 数据验证(表单验证、如手机、邮箱、IP地址) ② 数据检索(数据检索、数据抓取) ③ 数据隐藏(135****6235 王先生) ④ 数据过滤(敏感关键词过滤) …


5.2 正则表达式应用

一、正则表达式re模块

正则表达式单词: regular expression

python中的正则表达式模块: re

re 模块是 Python 内置的正则表达式处理模块,提供了强大的字符串匹配、查找、替换和分割功能。

re模块使用三大步:

​ 1.导包

​ 2.匹配数据

​ 3.处理数据

二、正则表达式匹配方式

1 匹配方式概述

匹配方式1: re.match(正则表达式,'要匹配的大字符串',标志位)

`match特点: 只能从开头开始匹配,只能返回第一个匹配成功的内容

匹配成功: 返回匹配对象,还需要从匹配对象中使用group()提取数据
匹配失败: 返回None
`

匹配方式2: re.search(正则表达式,'要匹配的大字符串',标志位)

`search特点: 可以整个字符串搜索,只能返回第一个匹配成功的内容

匹配成功: 返回匹配对象,还需要从匹配对象中使用group()提取数据
匹配失败: 返回None
`

匹配方式3: re.findall(正则表达式,'要匹配的大字符串',标志位)

`findall特点: 可以整个字符串搜索,可以返回所有匹配成功的内容

匹配成功: 返回的包含所有匹配成功数据的列表->[元素1,元素2,元素3...]
匹配失败: 返回空列表->[]
`

2 匹配方式练习

2.1 match匹配

`match匹配规则: 只从头开始匹配,只返回第一个匹配成功的数据

1.导包   : import re

2.匹配   : 匹配结果 = re.match(正则表达式,要匹配的大字符串内容)

3.处理数据: 如果匹配成功: 从返回的数据对象中把数据取出来    如果匹配失败: 返回None
`
`# 1.导包   : import re
import re

# 2.匹配   : 数据对象名 = re.match(正则表达式,要匹配的大字符串内容)
result = re.match('itheima', 'itheima.com')

# 3.处理数据: 从数据对象中把数据取出来
# 非空即为真(True)
if result:
    print('匹配成功:', result.group())
else:
    print('匹配失败!')
`

2.2 search匹配

`search匹配规则: 在整个大字符串中查找,只返回第一个匹配成功的数据

1.导包   : import re

2.匹配   : 匹配结果 = re.search(正则表达式,要匹配的大字符串内容)

3.处理数据: 如果匹配成功: 从返回的数据对象中把数据取出来    如果匹配失败: 返回None
`
`# 1.导包   : import re
import re

# 2.匹配   : 数据对象名 = re.search(正则表达式,要匹配的大字符串内容)
result = re.search('itheima', 'www.itheima.com')

# 3.处理数据: 从数据对象中把数据取出来
# 非空即为真(True)
if result:
    print('匹配成功:', result.group())
else:
    print('匹配失败!')
`

2.3 findall匹配

`search匹配规则: 在整个大字符串中查找,把所有匹配成功的数据放到列表中返回

1.导包   : import re

2.匹配   : 匹配结果 = re.findall(正则表达式,要匹配的大字符串内容)

3.处理数据: 如果匹配成功: 返回有内容的列表  如果匹配失败: 返回空列表
`
`# 1.导包   : import re
import re

# 2.匹配   : 数据对象名 = re.findall(正则表达式,要匹配的大字符串内容)
# 注意: findall匹配返回的是列表
result = re.findall('itheima', 'www.itheimaitheima.com')

# 3.处理数据: 打印列表
# 非空即为真(True)
if result:
    print('匹配成功:',result)
else:
    print('匹配失败!')
`

三、正则表达式匹配规则

1 正则匹配单个字符规则

知识点:

`记忆方式:  d:digit数字  s:space空白   w:word词

. : 任意1个字符(除了\n)
[]: 中括号中任意1个字符

\d: 任意1个数字(0-9)
\D: 非数字

\s: 任意1个空白(空格,\t,\n)
\S: 非空白

\w: 任意1个正常词(字母,数字,下划线,汉字)
\W: 非正常词(特殊字符)
`

示例:

`import re

# 定义一个函数用于处理数据
def show(result):
    if result:
        print('匹配成功:', result.group())
    else:
        print('匹配失败!')

print('-----------------------------------------------------------')

# . : 任意1个字符(除了\n)     举例:binzi_666_帅气->.inzi.6.6_帅.
result = re.match('.inzi.6.6_帅.', 'binzi_666_帅气')
show(result)
result = re.match('binzi_666.帅气', 'binzi_666\n帅气')
show(result)  # 匹配失败,因为.不能匹配\n
print('-----------------------------------------------------------')

# []: 中括号中任意1个字符   注意: 中括号里的内容是或者关系
result = re.match('[bB]inzi_666_帅气', 'binzi_666_帅气')
show(result)
result = re.match('[bB]inzi_[0-9][0-9][0-9]_帅气', 'binzi_888_帅气')
show(result)
print('-----------------------------------------------------------')

# \d: 任意1个数字(0-9)  \d==[0-9]==[0123456789]
result = re.match('binzi_\d\d\d_帅气', 'binzi_888_帅气')
show(result)
print('-----------------------------------------------------------')

# \D: 非数字
result = re.match('binzi_\D\D\D_帅气', 'binzi_888_帅气')
show(result)  # 匹配失败,因为\D代表非数字
result = re.match('\Dinzi\D888_帅\D', 'binzi_888_帅气')
show(result)
print('-----------------------------------------------------------')

# \s: 任意1个空白(空格,\t,\n)
result = re.match('binzi_666\s帅气', 'binzi_666 帅气')
show(result)
result = re.match('binzi_666\s帅气', 'binzi_666\t帅气')
show(result)
result = re.match('binzi_666\s帅气', 'binzi_666\n帅气')
show(result)
print('-----------------------------------------------------------')

# \S: 非空白
result = re.match('binzi_666\S帅气', 'binzi_666 帅气')
show(result)  # 匹配失败,因为\S匹配非空白
result = re.match('\Sinzi\S6\S6 帅\S', 'binzi_666 帅气')
show(result)
print('-----------------------------------------------------------')

# \w: 任意1个正常词(字母,数字,下划线,汉字)
result = re.match('\winzi\w6\w6_帅\w', 'binzi_666_帅气')
show(result)
print('-----------------------------------------------------------')

# \W: 非正常词(特殊字符)
result = re.match('\Winzi\W6\W6_帅\W', 'binzi_666_帅气')
show(result)  # 匹配失败,因为\W匹配特殊字符
result = re.match('binzi\W666\W帅气', 'binzi?666&帅气')
show(result)
`

2 正则匹配多个字符规则

知识点:

`* : 匹配前一个字符出现0次或者无限次     次数>=0

+ : 匹配前一个字符出现1次或者无限次     次数>=1

? : 匹配前一个字符出现0次或者1次       次数== 0 或者 次数 == 1

{x}: 匹配前一个字符出现x次            次数==x

{x,y}:匹配前一个字符出现x到y次        次数>=x 并且 次数<=y
`

示例:

`import re

# 定义一个函数用于处理数据
def show(result):
    if result:
        print('匹配成功:', result.group())
    else:
        print('匹配失败!')

# * : 匹配前一个字符出现0次或者无限次     次数>=0
result = re.match('[A-Z].*', 'Binzi666_帅气')  # 需求:第一个字母大写,后面内容任意
show(result)
result = re.match('t.*o', 'to')  # 需求: t和o中间可有可无任意字符
show(result)
result = re.match('张.*三', '张三')  # 需求: 张和三中间可有可无任意字符(姓名个数>=2)
show(result)
print('----------------------------------------------')

# + : 匹配前一个字符出现1次或者无限次     次数>=1   需求: t和o中间至少一个任意字符
result = re.match('t.+o', 'to')
show(result)  # 匹配失败,因为+要求至少1个
result = re.match('t.+o', 'tbo')
show(result)
result = re.match('t.+o', 'tbinzio')
show(result)
result = re.match('张.+三', '张三')  # 需求: 张和三中间至少加一个字(姓名个数>=3)
show(result)  # 匹配失败,因为+要求至少1个
print('----------------------------------------------')

# ? : 匹配前一个字符出现0次或者1次       次数== 0 或者 次数 == 1
result = re.match('https?', 'http')
show(result)
result = re.match('https?', 'https')
show(result)
print('----------------------------------------------')

# {x}: 匹配前一个字符出现x次            次数==x
result = re.match('binzi_[0-9]{3}_帅气', 'binzi_888_帅气')
show(result)
result = re.match('binzi_\d{3}_帅气', 'binzi_888_帅气')
show(result)
result = re.match('[a-zA-Z0-9_]{6}', 'abc_123')  # 需求: 密码6位
show(result)  # 注意此处有一个小的漏洞,一会儿使用匹配开头和结尾解决
print('----------------------------------------------')

# {x,y}:匹配前一个字符出现x到y次        次数>=x 并且 次数<=y
result = re.match('[a-zA-Z0-9_]{8,10}', 'abc_ABC_123_456')  # 需求: 密码是8-10位
show(result)  # 注意此处有一个小的漏洞,一会儿使用匹配开头和结尾解决
`

3 正则匹配开头和结尾

知识点:

`^ : 匹配以什么开头
$ : 匹配以什么结尾
注意: ^和$一般都是配合使用,起到限制作用
`

示例:

`import re

# 定义一个函数用于处理数据
def show(result):
    if result:
        print('匹配成功:', result.group())
    else:
        print('匹配失败!')

# 需求: 密码6位,多或者少都应该匹配失败
result = re.match('^[a-zA-Z0-9_]{6}$', 'abc_123')
show(result)  # 匹配失败,说明^和$起到了限制作用

result = re.match('^[a-zA-Z0-9_]{6}$', 'abc123')
show(result)

# 需求: 密码是8-10位,多或者少都应该匹配失败
result = re.match('^[a-zA-Z0-9_]{8,10}$', 'abc_ABC_123_456')
show(result)  # 匹配失败,说明^和$起到了限制作用

result = re.match('^[a-zA-Z0-9_]{8,10}$', 'abcABC123')
show(result)
`

4 正则匹配分组

知识点:

`| :   匹配左右任意一个表达式    或者

():   小括号中内容为一组,默认产生从1开始的编号

\n:   根据分组编号n引用对应的分组

(?P<name>) : 给分组起别名name

(?P=name) :  根据分组名name引用对应的分组
`

示例:

`import re

# 定义一个函数,用于处理数据
def show(data):
    if data:
        print('匹配成功:', data.group())
    else:
        print('匹配失败!')

# | :   匹配左右任意一个表达式    或者
# ():   小括号中内容为一组,默认产生从1开始的编号
# 需求.匹配出163,qq,sina的邮箱地址,且@符号之前有4到20位,举例: hello@163.com
result = re.match('([a-zA-Z0-9_]{4,20})@(163|qq|sina)\.com', 'binzi@qq.com')
show(result)
print(result.group(0)) # 0拿的是所有匹配成功的数据
print(result.group(1)) # 根据分组编号1,拿到对应的分组
print(result.group(2)) # 根据分组编号2,拿到对应的分组

# \n:   根据分组编号n引用对应的分组
result = re.match('<([a-zA-Z1-6]+)>.*</\\1>', '<html>标签内容</html>')
show(result)

# (?P<name>) : 给分组起别名name
# (?P=name) :  根据分组名name引用对应的分组
result = re.match('<(?P<name1>[a-zA-Z1-6]+)>.*</(?P=name1)>', '<html>标签内容</html>')
show(result)
`

5 特殊匹配

知识点:

`注意: 如果^放到了[]里面,表示取反作用

举例: [^\d] == [\D]
`

示例:

`"""
注意: 如果^放到了[]里面,表示取反作用
举例: [^\d] == [\D] == \D
"""

# 定义一个函数用于处理数据
def show(result):
    if result:
        print('匹配成功:', result.group())
    else:
        print('匹配失败!')

# 1.导包
import re

# 2.1匹配
result = re.match('[\D].*', 'hello')
# 3.1处理数据
show(result) # 非数字开头,匹配成功

# 2.2匹配
result = re.match('[^\d].*', 'hello')
# 3.2处理数据
show(result) # 非数字开头,匹配成功
`

四、综合练习

需求如下:

​ 1.匹配出微博中的话题, 举例: #幸福是奋斗出来的#

​ 2.匹配出11位手机号码, 举例: 18866668888

​ 3.匹配出163的邮箱地址,且@符号之前有4到20位,举例: hello@163.com

参考示例:

`import re

# 定义一个函数,用于处理数据
def show(data):
    if data:
        print('匹配成功:', data.group())
    else:
        print('匹配失败!')

# 1.匹配出微博中的话题, 举例: #幸福是奋斗出来的#
result = re.match('#.+#', '#幸福是奋斗出来的#')
show(result)
print('-----------------------------------')

# 2.匹配出11位手机号码, 举例: 18866668888
result = re.match('^1[0-9]{10}$', '18866668888')
show(result)
print('-----------------------------------')

# 3.匹配出163的邮箱地址,且@符号之前有4到20位,举例: hello@163.com
result = re.match('^[a-zA-Z0-9_]{4,20}@163.com$', 'binzi@163,com')
show(result)  # 应该报错,但是成功了,因为.有特殊含义: 除了\n的任意字符

# 知识点: 如果想要输出有特殊含义的字符,需要加转义符\,只代表本身含义
result = re.match('^[a-zA-Z0-9_]{4,20}@163\.com$', 'binzi@163,com')
show(result)
`

五、贪婪模式和非贪婪模式

知识点:

`贪婪模式: 在整个表达式匹配成功的前提下,尽可能多的匹配

非贪婪模式: 在整个表达式匹配成功的前提下,尽可能少的匹配

正则中的量词:*和+,默认都是贪婪模式的匹配,可以在他们后面加?将其变为非贪婪模式。

常用贪婪模式如: .*   .+

常用非贪婪模式如: .*?   .+?
`

示例:

`# 导包
import re

# 已知要匹配的字符串如下
my_str = '<h1>编程语言</h1>此处省略很多内容<h1>python大数据</h1>'

# .* : 贪婪模式,匹配成功的前提下,尽可能多的匹配
data = re.findall('<h1>.*</h1>', my_str)
print(data)  # ['<h1>编程语言</h1>此处省略很多内容<h1>python大数据</h1>']
print(len(data))  # 1

# .*?: 非贪婪模式,匹配成功的前提下,尽可能少的匹配
data = re.findall('<h1>.*?</h1>', my_str)
print(data)  # ['<h1>编程语言</h1>', '<h1>python大数据</h1>']
print(len(data))  # 2

# 需求: 只要标签中的标题名
# 知识点:findall匹配中如果有分组,那么只把对应分组里的内容放到列表中返回
data = re.findall('<h1>(.*?)</h1>', my_str)
print(data)  # ['编程语言', 'python大数据']
print(len(data))  # 2
`

六、正则修饰符

知识点:

`修饰符: 正则表达式可以包含一些可选标志修饰符来控制匹配的模式

常见的修饰符

re.I : 设置当前匹配不区分大小写

re.S : 设置.真正匹配到任意字符包含\n
`

示例:

`# 导包
import re

# 演示不区分大小写的匹配:re.I
# 注意: 验证码必须绝对匹配,可以使用^和$配合起到限制作用
data = re.findall('^a8D9$', 'A8d9', re.I)
print(data)  # ['A8d9']

# 演示.真正匹配到任意字符包含\n: re.S
print('------------------------')
my_str = '123\n456\n789'
print(my_str)
print('------------------------')
data = re.match('.{7}', my_str)
print(data)  # None  因为.不能匹配到\n
print('------------------------')
data = re.match('.{7}', my_str, re.S)
print(data.group())  # 123\n456  因为re.S让.匹配到了\n
`

扩展:正则工具箱

https://c.runoob.com/front-end/854/

基于 VitePress 构建 · 专注前端与 AI 实战