day07-python其他高级语法
一. with(上下文管理)
介绍
概述
一个类只要实现了__ enter __ () 和 __ exit __ ()方法, 这个类就是一个上下文管理器类, 该类的对象 = 上下文管理器对象
目的
节约资源, 提高效率, 避免手动释放资源, 且出bug的时候, 也会自动尝试释放资源
特点
-
上下文管理器对象, 可以结合with语句使用
-
在with语句执行前, 会自动调用__ enter __ () 方法(要有返回对象), 用于初始化某些变量
-
在with语句执行后, 会自动调用 __ exit __ ()方法, 用于清理某些资源, 即使前面有bug也会调用该方法
演示
案例: 自定义文件操作
# 1. 定义1个上下文管理器类, 表示: 我们自己的处理文件的操作.
class MyFile:
# 2. 在 init魔法方法中, 初始化: 属性信息.
def __init__(self, file_name, mode):
# 文件名(文件路径)
self.file_name = file_name
# 模式, r, w...
self.mode = mode
# 文件对象
self.file_obj = None
# 3. 在enter魔法方法中, 获取1个: 文件对象, 用于读写文件操作.
def __enter__(self):
print('我是 enter 魔法方法')
# 获取文件对象
self.file_obj = open(self.file_name, self.mode, encoding='utf-8')
# 返回文件对象.
# return self # self = MyFile的对象
return self.file_obj # file_obj = open()对象
# 4. 在exit魔法方法中, 关闭文件对象.
def __exit__(self, exc_type, exc_val, exc_tb):
self.file_obj.close()
print('文件对象已被关闭...')
# 5. 在main方法中, 测试自定义的 文件对象.
if __name__ == '__main__':
# 如果 enter魔法方法返回的是: open()对象, 代码如下
with MyFile('./1.txt', 'r') as file_obj:
# print( 10 / 0) # 即使有Bug, 也会尝试关闭资源.
data = file_obj.read()
print(f'读取到: {data}')
# 如果 enter魔法方法返回的是: MyFile对象, 代码如下.
# with MyFile('./1.txt', 'r') as mf:
# # print( 10 / 0) # 即使有Bug, 也会尝试关闭资源.
# data = mf.file_obj.read()
# print(f'读取到: {data}')
图解

二. 生成器
注意事项:
获取生成器生成的数据: next()函数, 遍历
如果使用超出生成式范围的数据,会报错
next()移动指针, 未使用生成器数据时, 指针停留在第一个数据前, 用完所有数据后指针停留在最后一个后面, 再次遍历输出为空, 直接取值报错(超出范围)
名词解释:
名词解释: 迭代 迭代指的是: 逐个的从容器类型中获取每一个元素的过程, 称之为: 迭代(遍历) 例如: 列表, 集合, 字典, 生成器等, 都是可以遍历(迭代)的, 所以它们也称之为: 可迭代对象.
介绍
概述
生成器指的是generator对象, 他不是像以往一样, 一次生成所有的数据, 而是用一个, 产生一个, 基于用户写的规则(条件)来生成数据, 如果条件不成立, 则结束生成
目的 | 好处
节约资源 , 减少内存的占用
生成器推导式
方式1: 推导式
尝试写一个'元组推导式'(没有元组推导式这种说法 => 它是生成器)
# 案例: 演示推导式写法, 获取生成器对象.
if __name__ == '__main__':
# 1. 回顾: 列表推导式.
list1 = [i for i in range(1, 6)]
print(f'list1: {list1}') # [1, 2, 3, 4, 5]
print(f'list1的类型: {type(list1)}') # <class 'list'>
# 2. 回顾: 字典推导式.
dict1 = {i: i ** 2 for i in range(1, 6)}
print(f'dict1: {dict1}')
print(f'dict1的类型: {type(dict1)}') # <class 'dict'>
# 3. 回顾: 集合推导式.
set1 = {i for i in range(1, 6)}
print(f'set1: {set1}')
print(f'set1的类型: {type(set1)}') # <class 'set'>
print('-' * 21)
# 4. 尝试写1个"元组推导式", 注意: 没有元组推导式这个说法, 它的底层是: 生成器对象.
# 生成器写法1: 推导式写法.
my_generator = (i for i in range(1, 6))
print(f'my_generator: {my_generator}') # 地址值
print(f'my_generator的类型: {type(my_generator)}') # <class 'generator'>
print('-' * 21)
# 5. 生成器不是一下子生成所有的数据, 而是用一个再生成1个.
# 问: 如何从生成器中获取数据呢?
# 答: 1: next()函数. 2.for循环遍历.
# 方式1: next()函数, 从生成器中获取数据.
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
print(next(my_generator))
# print(next(my_generator)) # 报错: StopIteration, 停止迭代
print('-' * 21)
# 方式2: for循环遍历, 获取生成器的数据
# 细节: next()是移动指针的, 获取下个元素, 如果不注释上边的代码, 这里打印结果是 空.
for i in my_generator:
print(i)
yield
方式2:yield关键字
# 需求: 获取 1 ~ 10之间的整数, 生成器写法.
# 1. 定义函数, 获取: 生成器对象.
def get_generator():
# 回顾: list写法
# list_data = []
# for i in range(1, 11):
# list_data.append(i)
# return list_data # 返回列表对象
# 对比: yield写法, 效果类似于上边的代码, 只不过返回的是: 生成器对象.
for i in range(1, 11):
yield i # yield的作用: 1.创建生成器对象. 2.逐个的把每个元素放到生成器对象中. 3.函数结束时, 返回生成器对象.
# 2. 测试上述的函数.
if __name__ == '__main__':
# 3. 调用函数, 获取生成器对象.
my_generator = get_generator()
print(type(my_generator)) # <class 'generator'>
# 4. 从生成器对象中, 获取数据.
# 方式1: next()函数
print(next(my_generator)) # 1
print(next(my_generator)) # 2
print(next(my_generator)) # 3
print('-' * 21)
# 方式2: 遍历.
for i in my_generator:
print(i)
案例
分批次读取数据
需求:
自定义数据迭代器, 按照指定的条数生成批次数据, 为后续的AI模型训练课做准备.未来我们训练模型的时候, 是把数据分批次喂给模型的, 而不是一次性喂养.
# 分批加载数据
def data_loader(batch_size):
with open('./jaychou_lyrics.txt', 'r', encoding='utf-8') as f:
data = f.readlines()
# 根据批次的数据量, 遍历批次,
# 批次数 = (数据总条数 + 每批次的数据条数 -1) // 每批次的数据条数
for i in range((len(data) + batch_size - 1) // batch_size):
yield data[i * batch_size: i * batch_size + batch_size]
if __name__ == '__main__':
data = data_loader(8)
print(next(data))
import math
# 案例1: 扩展 math#ceil()函数, 获取天花板数, 即: 比这个数字大的所有整数中, 最小的那个整数.
# 总条数: 100条, 8条/批次, 问: 共多少批次? 13批
# print(math.ceil(5.0)) # 5
# print(math.ceil(5.1)) # 6
# print(math.ceil(5.6)) # 6
# print(math.ceil(21.6)) # 22
# print(math.ceil(100 / 8)) # 13
# 案例2: 定义函数 dataset_loader(batch_size), 用于获取: 批次数据.
def dataset_loader(batch_size):
"""
自定义的函数, 获取批次数据的.
:param batch_size: 每批次数据的条数.
:return: 生成器对象, 每个数据 = 1批的数据
"""
# 1. 读取源文件, 获取到所有的数据.
with open('./data/jaychou_lyrics.txt', 'r', encoding='utf-8') as src_f:
# 一次性读取所有的行, 并放到列表中.
list_data = src_f.readlines() # 数据格式: ['第1行\n', '第2行\n', '第3行\n'...]
# 2. 获取数据的总条数.
line_count = len(list_data)
# 3. 根据数据的总条数, 结合每批次的数据条数, 计算: 总批次数.
batch_count = math.ceil(line_count / batch_size)
# 4. 遍历 总批次数, 获取到: 每个批次的 编号, 然后生成: 该批次的数据.
for batch_idx in range(batch_count):
"""
推理过程:
假设 batch_size = 8, batch_count = 13, 即: 13批, 8条/批, 则:
batch_idx = 0, 代表第1批数据, 数据为: 第1条 ~ 第8条, 索引为: [0:8]
batch_idx = 1, 代表第2批数据, 数据为: 第9条 ~ 第16条, 索引为: [8:16]
batch_idx = 2, 代表第3批数据, 数据为: 第17条 ~ 第24条, 索引为: [16:24]
......
"""
yield list_data[batch_idx * batch_size: batch_idx * batch_size + batch_size]
# 在main函数中测试.
if __name__ == '__main__':
# 5. 获取生成器对象.
data_loader = dataset_loader(batch_size=8)
# 6. 获取第1批次的数据.
# print(next(data_loader))
batch_data1 = next(data_loader)
# 具体的获取第1批次中每条数据的过程.
for line in batch_data1:
print(line, end='')
print('-' * 21)
# 7. 获取第2批次的数据.
print(next(data_loader))
三. property
介绍
概述:
它是用来修饰函数的, 修饰之后, 可以把函数 当做 变量来使用.
目的/作用:
简化开发, 提高效率.
充当装饰器
property充当装饰器的具体用法 1. 在 获取值的函数上, 加上 @property
在 设置值的函数上, 加上 @方法名.setter,
注意: 这里的方法名是@property修饰的方法名
3. 之后就可以把 函数 当做 变量来直接使用了.
格式1
获取与修改函数不同名
# 需求: 定义学生类, 有个私有的属性name, 提供公共的访问方式, 并测试.
# 1. 定义学生类.
class Student:
# 2. 私有属性.
def __init__(self):
self.__name = '张三' # 私有属性.
# 3. 获取值的方法.
# @property
# def get_name(self):
# return self.__name
#
# # 4. 设置值的方法.
# @get_name.setter
# def set_name(self, name):
# self.__name = name
# 5. get_xxx(), set_xxx()函数 如果结合 property装饰器用, 具体写法如下:
# 获取值的方法
@property
def name(self):
return self.__name
# 设置值的方法.
@name.setter
def name(self, name):
# 根据需求, 可以对传入的值做校验.
# if name == '段誉':
# print('名字不能为段誉')
# else:
# self.__name = name
# 直接赋值.
self.__name = name
# 在main中测试.
if __name__ == '__main__':
# 6. 创建学生对象.
s = Student()
# 7. 访问Student类的私有属性name
# print(s.name) # 报错
# print(s.__name) # 报错.
# s.set_name('乔峰')
# print(s.get_name())
# 8. 访问Student类的私有属性name
# s.set_name = '虚竹'
# print(s.get_name)
# 看起来调用的是"属性", 其实底层是: 函数.
s.name = '段誉'
print(s.name)
格式2
获取与修改函数同名
# 定义学生类
class Student(object):
# 定义私有属性
def __init__(self):
self.__name = '张三'
# # 定义函数访问私有属性
# def get_name(self):
# return self.__name
#
# # 定义函数修改私有属性
# def set_name(self, name):
# self.__name = name
# 使用property定义函数变量
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
# 可以增加校验, 具体看需求
# if name == '李四':
# print(f'name不能为{name}')
# else:
# self.__name = name
self.__name = name
if __name__ == '__main__':
s = Student()
s.name = '李四'
print(s.name)
充当类属性
property充当 类属性 的具体用法
直接在类中编写 类变量名 = property(获取值的方法名, 设置值方法名)
之后就可以通过 类名.类变量名的方式 来使用了, 这个是充当: 类量的.
如果要精准的修改或者获取某个学生的信息, 可以通过 对象名.性名的方式调用.
演示
# 需求: 定义学生类, 有个私有的属性name, 提供公共的访问方式, 并测试.
# 1. 定义学生类.
class Student:
# 2. 私有属性.
def __init__(self):
self.__name = '张三' # 私有属性.
# 3. 获取值的方法.
def get_name(self):
return self.__name
# 4. 设置值的方法.
def set_name(self, name):
self.__name = name
# 5. property充当类属性的用法.
# 参1: 获取值的函数.
# 参2: 设置值的函数.
# 注意: 顺序不要写反了, 这个是固定的顺序, 写反了会报错.
name = property(get_name, set_name)
# 在main中测试.
if __name__ == '__main__':
# 6. 创建学生对象.
s = Student()
s.name = '乔峰' # 对象属性
# Student.name = '乔峰' # 类属性
print(s.name)
print('-' * 21)
# 7. 再次创建学生对象.
s2 = Student()
print(s2.name)
四. 正则
概述
正确的, 符合特定规则的 字符串. 英文名叫: Regular Expression,
简称叫: re, RegExp
作用
主要用于 校验数据.
细节
-
学正则, 主要是学正则的规则. 即: 哪个符号表示什么含义.
-
关于正则, 要求很简单, 只要能用我们讲的规则, 看懂别人写的 式子, 且能简单修改即可, 无需你手动编写.
-
到目前为止, 正则已经经历了N长的时间, 几乎你遇到的绝大多数的正则校验, 前辈们都已经写过了(帮我们写好了).
-
正则不独属于Python, 例如: Java, C#, JavaScript, Go...等众多的语言都支持, 且: 正则的规则都是一样的.
python中正则的调用
步骤
-
导包import re
-
正则匹配校验.result = re.match(正则规则, 要被校验的字符串, 扩展选项-例如区分大小写, 空值过滤...) 全词匹配, 从左往右依次匹配result = re.search(正则规则, 要被校验的字符串, 扩展选项-例如区分大小写, 空值过滤...) 分段批次, 任意一段能匹配即可.result = re.compile(...).sub(...) 用于做替换的
-
获取匹配到的数据.result.group()
演示
入门
# 需求1: 正则表达式入门.
# 导包
import re
# 校验字符串是否是 任意字符 + it + 任意字符.
result = re.match('.it.', 'aitb') # 可以匹配
result = re.match('.it.', 'ait\n') # 未匹配
result = re.match('.it.', 'ait') # 未匹配
# 获取到匹配的结果.
if result:
# 走这里, 有值, 获取到匹配的数据, 打印即可.
print(result.group())
else:
# 走这里, 没有匹配到数据, 打印即可.
print('未匹配到!')
print('-' * 21)
替换
案例: 演示 正则替换, 即: 把符合正则规则的内容, 用指定的内容来替换.
格式: import re re.compile(正则规则).sub(新字符串, 旧字符串) 去旧字符串中, 找到符合正则规则的内容, 用新字符串来替换.
上述格式的语法糖: re.sub(正则规则, 新字符串, 旧字符串) 去旧字符串中, 找到符合正则规则的内容, 用新字符串来替换.
回顾: 字符串的 replace()函数, 也是替换的, 但是不支持正则. 快捷键: alt + enter: 给出建议的意思.
import re
if __name__ == '__main__':
# 案例1: 把下述的符合正则规则的内容, 用*来替换.
# 1. 定义 旧字符串.
old_str = '你可以这样: 桀1桀2桀, 哈3哈, 呵A呵, 嘿嘿, 嘻嘻, 略略略, 嘤嘤嘤...'
# 2. 定义 正则规则(字符串形式)
reg_exp = '桀|哈|呵|嘿|嘻'
# 3. 把符合正则规则的内容, 用*来替换.
# 分解版写法.
# 3.1 获取正则对象.
# re_obj = re.compile(reg_exp)
# 3.2 具体的替换过程.
# result = re_obj.sub('*', old_str)
# 合并版写法, 正则规则 新内容 旧内容
# result = re.compile(reg_exp).sub('*', old_str)
# 上述格式的语法糖, 正则规则 新内容 旧内容
result = re.sub(reg_exp, '*', old_str)
# 4 打印结果
print(result)
print('-' * 21)
# 案例2: 回顾字符串的replace()函数.
s1 = '抽烟只抽煊赫门, 一生只爱一个人. 其他烟: 中华, 煊赫门, 天叶, 煊赫门...'
# result = s1.replace('煊赫门', '*') # 不写次数, 默认替换所有.
# result = s1.replace('煊赫门', '*', 1) # 只替换1次(个)
result = s1.replace('煊赫门|中华|天叶', '*')
print(f'result: {result}')
常用规则
单字符
""" 涉及到的正则的规则: . 代表: 任意的1个字符, \n除外 \. 代表: 1个普通的. 即: 取消.的特殊含义 a 代表: 1个字符a [abc] 代表: a, b, c中任意的1个字符, 即: 要么a, 要么b, 要么c [^abc] 代表: 除了a,b,c外, 任意的1个字符 \d 代表: 任意的1个整数, 等价于 [0-9] \D 代表: 任意的1个非整数, 等价于 [^0-9] \w 代表: 非特殊字符, 即: 大小写英文字符, 数字, _, 汉字 \W 代表: 特殊字符, 即: \w 取反. \s 代表: 空白字符, 例如: 空格, \t... \S 代表: 非空白字符, 即: \s取反. """
# 导包
import re
# 在main中测试
if __name__ == '__main__':
# 演示: . 代表: 任意的1个字符, \n除外
result = re.match('it.', 'ita') # ita
result = re.match('it.', 'it\t') # it\t
result = re.match('it.', 'it\n') # 未匹配
# 演示: \. 代表: 1个普通的. 即: 取消.的特殊含义
# 细节: 为了防止打印异常信息, 你可以写成: r'it\.' 或者 'it\\.'
result = re.match('it\\.', 'ita') # 未匹配
result = re.match('it\\.', 'it.') # it.
result = re.match('it\\.', 'it.abc') # it.
# 演示: a 代表: 1个字符a
result = re.match('a', 'abc') # a
result = re.match('a', 'xyz') # 未匹配
# 演示: [abc] 代表: a, b, c中任意的1个字符, 即: 要么a, 要么b, 要么c
result = re.match('it[abc]', 'itabc') # ita
result = re.match('it[abc]', 'itbc') # itb
result = re.match('it[abc]', 'itd') # 未匹配
# 演示: [^abc] 代表: 除了a,b,c外, 任意的1个字符
result = re.match('it[^abc]', 'itabc') # 未匹配
result = re.match('it[^abc]', 'itbc') # 未匹配
result = re.match('it[^abc]', 'itd') # itd
# 演示: \d 代表: 任意的1个整数, 等价于 [0-9]
result = re.match('hm[0-9]', 'hm1') # hm1
result = re.match('hm[0-9]', 'hm3a') # hm3
result = re.match(r'hm\d', 'hm3a') # hm3
result = re.match(r'hm\d', 'hma') # 未匹配
# 演示: \D 代表: 任意的1个非整数, 等价于 [^0-9]
result = re.match(r'hm\D', 'hma') # hma
result = re.match(r'hm\D', 'hm3a') # 未匹配
# 演示: \w 代表: 非特殊字符, 即: 大小写英文字符, 数字, _, 汉字
result = re.match(r'hm\w', 'hma') # hma
result = re.match(r'hm\w', 'hmB') # hmB
result = re.match(r'hm\w', 'hm1') # hm1
result = re.match(r'hm\w', 'hm_') # hm_
result = re.match(r'hm\w', 'hm!') # 未匹配
# 演示: \W 代表: 特殊字符, 即: \w 取反.
result = re.match(r'hm\W', 'hm!') # hm!
result = re.match(r'hm\W', 'hm_') # 未匹配
# 演示: \s 代表: 空白字符, 例如: 空格, \t...
result = re.match(r'hm\s', 'hm') # 未匹配
result = re.match(r'hm\s', 'hm ') # hm
result = re.match(r'hm\s', 'hm\t') # hm
result = re.match(r'hm\s', 'hm\n') # hm\n
result = re.match(r'hm\s', 'hma') # 未匹配
# 演示: \S 代表: 非空白字符, 即: \s取反.
# 自己测试.
# 打印校验到的数据.
if result:
print(f'匹配到: {result.group()}')
else:
print('未匹配!')
多字符
"""
涉及到的正则的规则如下, 都是和 数量词 有关:
? 代表: 前边的内容, 出现0次 或者 1次
* 代表: 前边的内容, 至少出现0次, 至多出现n次(无数次)
+ 代表: 前边的内容, 出现1次 或者 多次.
a{n} 代表: a恰好出现n次, 多一次少一次都不行.
a{n,} 代表: a至少出现n次, 至多无所谓.
a{n,m} 代表: a至少出现n次, 至多出现m次, 包括n 和 m
"""
# 导包
import re
# main中测试
if __name__ == '__main__':
# 演示: ? 代表: 前边的内容, 出现0次 或者 1次
result = re.match('it.?', 'it')
result = re.match('it.?', 'it ')
result = re.match('it.?', 'itabcABC')
result = re.match('it.?', 'it\nABC') # it
# 演示: * 代表: 前边的内容, 至少出现0次, 至多出现n次(无数次)
result = re.match('it[abc]*', 'it\nABC') # it
result = re.match('it[abc]*', 'itabcABC') # itabc
result = re.match('it[abc]*', 'it ') # it
result = re.match('it[abc]*', 'it') # it
# 演示: + 代表: 前边的内容, 出现1次 或者 多次.
result = re.match('it[abc]+', 'it') # 未匹配
result = re.match('it[abc]+', 'it ') # 未匹配
result = re.match('it[abc]+', 'it\nABC') # 未匹配
result = re.match('it[abc]+', 'itabcABC') # itabc
# 演示: a{n} 代表: a恰好出现n次, 多一次少一次都不行.
result = re.match('it[abc]{2}', 'itabcABC') # itab
result = re.match('it[abc]{2}', 'itacb') # itac
result = re.match('it[abc]{2}', 'ita') # 未匹配
# 演示: a{n,} 代表: a至少出现n次, 至多无所谓.
result = re.match('it[abc]{2,}', 'ita') # 未匹配
result = re.match('it[abc]{2,}', 'itacb') # itacb
result = re.match('it[abc]{2,}', 'itabcABC') # itabc
# 演示: a{n,m} 代表: a至少出现n次, 至多出现m次, 包括n 和 m
result = re.match('it[abc]{2,3}', 'itabcde') # itabc
result = re.match('it[abc]{2,3}', 'ita') # 未匹配
# 打印结果.
print(f'匹配到: {result.group()}' if result else '未匹配!')
开始和结束
""" ^ 代表开头 $ 代表结尾 """
import re
if __name__ == '__main__':
# 演示: ^ 代表: 正则表达式的 开头
# 需求: 校验字符串必须以 it 开头.
result = re.match(r'it\d', 'it123') # it1
result = re.match(r'it\d', '1it123') # 未匹配!
result = re.search(r'it\d', 'it123') # it1
result = re.search(r'it\d', '1it123') # it1
# ^代表开头, 即: 如下的代码其实是 全词匹配, 必须从字符串的第1个字符开始校验.
result = re.search(r'^it\d', '1it123') # 未匹配!
# 演示: $ 代表: 正则表达式的 结尾
# 需求: 校验字符串必须以 数字 结尾.
result = re.match(r'it\d', 'it123a') # it1
result = re.match(r'it\d$', 'it123a') # 未匹配!
# 扩展: 校验手机号.
# 规则: 1. 必须以1开头. 2.第2位数字可以是3 ~ 9. 3.必须是纯数字. 4.长度必须是11位.
result = re.match(r'^1[3-9]\d{9}$', '13112345678a')
result = re.match(r'^1[3-9]\d{9}$', '13112345678')
# 打印匹配到的结果.
print(result.group() if result else '未匹配!')
分组
""" | 代表: 或者的意思 () 代表: 分组 \num 代表: 获取第num组的内容 扩展: (?P<分组名>) 设置分组 (?P=分组名) 获取指定分组的内容 细节: 正则默认属于第0组, 之后就按照 左小括号来数, 是第几个, 就是第几组. """
或
import re
if __name__ == '__main__':
# 需求1: 在列表中, 打印用户喜欢吃 和 不喜欢吃的水果.
# 1. 定义水果列表.
fruits = ['apple', 'banana', 'orange', 'pear']
# 2. 遍历, 获取每种水果.
for fruit in fruits:
# 3. 假设用户喜欢吃 香蕉, 梨, 判断即可.
result = re.match('banana|pear', fruit)
# 4. 打印结果.
if result:
print(f'喜欢吃: {fruit}')
else:
print(f'不喜欢吃: {fruit}')
分组(验证邮箱案例)
import re
if __name__ == '__main__':
# 需求: 匹配出 163, 126, qq等邮箱.
# 邮箱规则: 前边是4 ~ 20位的字母, 数字, 下划线 + @标记符 + 域名
# 1. 定义邮箱字符串.
email_str = 'zhangsan@163com'
email_str = 'zhangsan@1634.com'
email_str = 'zh@qq.com'
email_str = 'zhangsan@163.com'
# 2. 定义 校验邮箱的 正则表达式.
pattern = r'^[a-zA-Z0-9_]{4,20}@(163|126|qq)\.com$'
# 3. 校验邮箱.
result = re.match(pattern, email_str)
# 4. 打印结果.
if result:
print(f'匹配到: {result.group()}') # zhangsan@163.com, 等价于 result.group(0), 即: 获取所有匹配到的数据
print(f'匹配到: {result.group(0)}') # zhangsan@163.com, 效果同上.
print(f'匹配到: {result.group(1)}') # 163
else:
print('未匹配!')
提取指定分组
import re
if __name__ == '__main__':
# 需求: 匹配 qq:qq号 这样的数据, 提取出 qq文字 和 qq号码.
# 1. 定义字符串.
s1 = "qq:1234567"
# 2. 匹配数据.
result = re.match(r'(qq):(\d{6,11})', s1)
# 3. 打印匹配到的数据.
if result:
print(f'匹配到: {result.group()}') # qq:1234567
print(f'匹配到: {result.group(0)}') # qq:1234567
print(f'匹配到: {result.group(1)}') # qq
print(f'匹配到: {result.group(2)}') # 1234567
else:
print('未匹配!')
分组后起别名
引用指定分组
import re
if __name__ == '__main__':
# 需求1: 正则校验 html标签, 简单版.
# 1. 定义html标签字符串.
html_str1 = '<html>AI就业21期</html>'
# 2. 正则校验.
# 假设: 标签规则: 2到4位字母
result = re.match('<[a-zA-Z]{2,4}>.*</[a-zA-Z]{2,4}>', html_str1)
# 上述格式优化版, 加入: 分组思想.
result = re.match(r'<([a-zA-Z]{2,4})>.*</\1>', html_str1)
# 3. 打印匹配结果.
if result:
print(f'匹配到: {result.group()}')
else:
print('未匹配!')
print('-' * 21)
# 需求2: 正则校验 html标签, 升级版.
# 假设: 外部标签规则 2到4位字母, 内部标签规则: h + 1到6的数字
# 1. 定义html标签字符串.
html_str2 = '<html><h1>AI就业21期</h1></html>'
# 2. 正则校验
result = re.match(r'<[a-zA-Z]{2,4}><h[1-6]>.*</h[1-6]></[a-zA-Z]{2,4}>', html_str2)
# 加入分组, 优化上述的代码.
result = re.match(r'<([a-zA-Z]{2,4})><(h[1-6])>.*</\2></\1>', html_str2)
# 扩展: 给分组设置组名.
result = re.match(r'<(?P<A>[a-zA-Z]{2,4})><(?P<B>h[1-6])>.*</(?P=B)></(?P=A)>', html_str2)
# 3. 打印匹配结果.
if result:
print(f'匹配到: {result.group()}')
else:
print('未匹配!')



















