Python知识学习08

第一部分:Python 文件IO基础

1 文件 IO 概念

1.1 基本定义

  • 文件 IO:即文件 Input/Output,实现程序与操作系统之间的文件数据交互。

  • 输入流(Input):将文件中的数据读取到内存(程序)中。

  • 输出流(Output):将内存(程序)中的数据写入到文件中。

  • 核心函数 :Python 内置 open() 函数,用于打开文件并返回数据流(输入流 / 输出流),操作失败会抛出 OSError 异常。

1.2 文件分类(操作系统层面)

文件类型 底层组成 校验方式 典型示例
字符文件 字符(文本) 记事本打开无乱码 源代码文件(.py)、配置文件(.txt)、文档(.md)
字节文件 字节 / 二进制 记事本打开会乱码 图片(.jpg/.png)、音频(.mp3)、视频(.mp4)、压缩包(.zip)

1.3 open () 函数

1.3.1 语法

复制代码
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

1.3.2 参数说明

参数 功能 关键注意事项
file 文件路径(相对路径 / 绝对路径) Windows 路径分隔符可用 \\/(避免转义问题)
mode 操作模式(控制读写方式、文件类型) 由 "操作符 + 类型符" 组合,默认 r(文本读)
encoding 字符编码(仅字符文件需要) 常用 UTF-8,字节文件无需指定
buffering 缓冲策略 默认 -1(系统自动缓冲),无需手动设置

1.3.3 mode 参数组合

模式组合 功能描述 适用文件类型
r / rt 文本读(默认) 字符文件
w / wt 文本写(覆盖原有内容,文件不存在则创建) 字符文件
a / at 文本追加(在文件尾部写入,文件不存在则创建) 字符文件
rb 字节读 字节文件
wb 字节写(覆盖原有内容) 字节文件
ab 字节追加 字节文件
r+ / rt+ 文本读写(可同时读和写) 字符文件
rb+ 字节读写 字节文件
x / xt / xb 新建文件并写(文件已存在则报错) 字符 / 字节文件

2 字符文件操作(文本文件)

字符文件操作需指定 encoding(如 UTF-8),避免中文乱码。核心流程:打开文件 → 读写数据 → 关闭文件

2.1 写入字符文件

2.1.1 基础语法(open () + close ())

复制代码
# 1. 准备文本数据
content = "hello python!\n你好,Python 文件IO!"

# 2. 打开文件:mode="wt"(文本写),指定编码 UTF-8
file = open("test01.txt", mode="wt", encoding="UTF-8")

# 3. 写入数据:write() 接收字符串
file.write(content)

# 4. 关闭文件(必须执行,释放资源)
file.close()

2.1.2 高级语法(with 语句,自动关闭)

with 语句会自动封装 "打开→操作→关闭" 流程,避免遗漏 close(),优先使用:

复制代码
# 自动打开文件,执行完代码块后自动关闭
with open("test02.txt", mode="wt", encoding="UTF-8") as file:
    file.write("使用 with 语句写入文本数据")

2.2 读取字符文件

2.2.1 基础读取(读取全部内容)

复制代码
# mode="rt" 可省略(默认 r),必须指定 encoding
with open("test01.txt", encoding="UTF-8") as file:
    # read():读取文件全部内容,返回字符串
    data = file.read()
    print("读取结果:")
    print(data)

2.2.2 进阶读取方法

方法 功能 示例
read(size) 读取指定长度的字符(size 为字符数) file.read (10) → 读取前 10 个字符
readline() 读取一行数据(以 \n 为分隔) 逐行读取大文件时避免内存溢出
readlines() 读取所有行,返回列表(每行作为一个元素) lines = file.readlines () → 列表推导式处理每行

2.2.3 逐行读取大文件(推荐)

复制代码
# 逐行读取,适合超大文本文件(避免一次性加载全部内容)
with open("large_file.txt", encoding="UTF-8") as file:
    for line in file:  # 直接迭代文件对象,逐行读取
        print(line.strip())  # strip() 去除换行符和空格

2.3 字符文件操作注意事项

  • 写入后必须关闭文件(或用 with 语句),否则数据可能未真正写入(缓冲区未刷新)。

  • 读取时必须指定正确的 encoding,否则中文会乱码。

  • 若文件不存在,r 模式会报错,w/a/x 模式会自动创建文件。

3 字节文件操作(二进制文件)

字节文件操作模式需带 b(如 rb/wb),无需指定 encoding ,数据以字节串(bytes 类型,前缀 b)处理。

3.1 读取字节文件(如图片、视频)

复制代码
# 读取图片文件(字节文件)
with open("test.jpg", mode="rb") as file:
    # read() 返回字节串(bytes 类型)
    byte_data = file.read()
    print("字节数据长度:", len(byte_data))
    print("前10个字节:", byte_data[:10])  # 切片查看部分字节

3.2 写入字节文件

字节数据需用 b'' 表示(或通过 str.encode(encoding) 转换):

复制代码
# 方式1:直接定义字节串
byte_content1 = b"hello world!"  # 英文直接加 b 前缀

# 方式2:字符串编码为字节串(中文需指定编码)
byte_content2 = "你好,字节文件!".encode("UTF-8")

# 写入字节文件(mode="wb")
with open("test03.bin", mode="wb") as file:
    file.write(byte_content1)
    file.write(b"\n")  # 字节换行符
    file.write(byte_content2)

3.3 字节与字符串转换

转换方向 方法 示例
字符串 → 字节 str.encode(encoding) "中文".encode ("UTF-8") → 字节串
字节 → 字符串 bytes.decode(encoding) b'\xe4\xb8\xad\xe6\x96\x87'.decode ("UTF-8") → 字符串

4 综合实战:文件复制(支持所有文件类型)

文件复制的核心是字节流操作(适配字符文件和字节文件),大文件需分块读取,避免内存溢出。

4.1 基础版:大文件分块复制

复制代码
import os

def copy_file(source_path, target_path, chunk_size=1024*1024):
    """
    大文件分块复制(支持所有文件类型)
    :param source_path: 源文件路径(必须是完整文件路径)
    :param target_path: 目标文件路径(必须包含文件名)
    :param chunk_size: 分块大小(默认 1MB,可调整)
    """
    # 检查源文件是否存在
    if not os.path.exists(source_path):
        raise FileNotFoundError(f"源文件不存在:{source_path}")
    
    # 确保目标文件所在目录存在
    target_dir = os.path.dirname(target_path)
    if not os.path.exists(target_dir):
        os.makedirs(target_dir)
    
    # 分块读写(字节模式)
    with open(source_path, "rb") as src_file, open(target_path, "wb") as tgt_file:
        while True:
            # 每次读取 chunk_size 字节
            chunk = src_file.read(chunk_size)
            if not chunk:  # 读取到空字节串,说明文件结束
                break
            tgt_file.write(chunk)  # 分块写入
    
    print(f"文件复制完成:{source_path} → {target_path}")

# 调用函数:复制 ISO 镜像文件
if __name__ == "__main__":
    source = "F:/BaiduNetdiskDownload/ubuntu-24.10-desktop-amd64.iso"
    target = "D:/bat/ubuntu_copy.iso"
    copy_file(source, target)

4.2 进阶版:带进度提示的复制(tqdm 进度条)

需先安装:pip install tqdm

复制代码
from tqdm import tqdm
import os

def copy_file_with_progress(source_path, target_path, chunk_size=1024*1024):
    """带进度条的文件复制"""
    if not os.path.exists(source_path):
        raise FileNotFoundError(f"源文件不存在:{source_path}")
    
    # 获取源文件总大小(用于进度计算)
    total_size = os.path.getsize(source_path)
    target_dir = os.path.dirname(target_path)
    if not os.path.exists(target_dir):
        os.makedirs(target_dir)
    
    # 打开文件并创建进度条
    with open(source_path, "rb") as src_file, open(target_path, "wb") as tgt_file:
        # tqdm 进度条配置:总大小、单位、自动缩放
        with tqdm(
            total=total_size,
            unit="B",
            unit_scale=True,
            desc=f"复制 {os.path.basename(source_path)}"
        ) as progress_bar:
            while True:
                chunk = src_file.read(chunk_size)
                if not chunk:
                    break
                tgt_file.write(chunk)
                # 更新进度条(每次更新读取的字节数)
                progress_bar.update(len(chunk))
    
    print(f"\n✅ 文件复制完成:{target_path}")

# 测试
if __name__ == "__main__":
    source = "F:/BaiduNetdiskDownload/ubuntu-24.10-desktop-amd64.iso"
    target = "D:/bat/ubuntu_with_progress.iso"
    copy_file_with_progress(source, target)

4.3 文件复制常见问题

  • 路径问题 :Windows 路径分隔符可用 \\(转义)或 /(推荐);目标路径必须包含文件名。

  • 权限问题:操作系统目录需管理员权限。

  • 大文件处理:分块大小推荐 1MB~8MB,平衡速度与内存。

5 抽象数据的 IO 操作(序列化与反序列化)

抽象数据:列表、字典、元组等非字符 / 字节类型。

  • 序列化:对象 → 文件可存储格式

  • 反序列化:文件 → 原始对象

5.1 pickle 模块(字节序列化,支持所有 Python 对象)

5.1.1 序列化(对象 → 字节文件)

复制代码
import pickle

# 准备抽象数据(字典、列表混合)
user_data = {
    "admin": {"username": "admin", "password": "123456", "age": 25},
    "manager": {"username": "manager", "password": "654321", "roles": ["user", "admin"]}
}

# 序列化到字节文件(mode="wb")
with open("user_data.dat", mode="wb") as file:
    pickle.dump(user_data, file)  # dump():将对象写入文件

print("✅ 数据序列化完成")

5.1.2 反序列化(字节文件 → 对象)

复制代码
import pickle

# 从字节文件反序列化
with open("user_data.dat", mode="rb") as file:
    loaded_data = pickle.load(file)  # load():读取文件并恢复对象

# 验证数据(类型和内容不变)
print("反序列化后数据类型:", type(loaded_data))
print("反序列化后数据:", loaded_data)
print("admin 密码:", loaded_data["admin"]["password"])

5.2 json 模块(字符序列化,跨语言兼容)

5.2.1 序列化(对象 → JSON 文件)

复制代码
import json

# 准备基础抽象数据(仅支持 JSON 兼容类型)
product_data = {
    "id": 1001,
    "name": "Python 编程从入门到实践",
    "price": 89.0,
    "tags": ["编程", "Python", "入门"],
    "is_stock": True
}

# 序列化到 JSON 文件(mode="wt",指定 encoding)
with open("product.json", mode="wt", encoding="UTF-8") as file:
    # indent:格式化输出;ensure_ascii=False:支持中文
    json.dump(product_data, file, indent=4, ensure_ascii=False)

print("✅ JSON 序列化完成")

5.2.2 反序列化(JSON 文件 → 对象)

复制代码
import json

# 从 JSON 文件反序列化
with open("product.json", encoding="UTF-8") as file:
    loaded_product = json.load(file)

print("反序列化后数据类型:", type(loaded_product))
print("产品名称:", loaded_product["name"])
print("产品标签:", loaded_product["tags"])

5.3 序列化模块对比

模块 序列化格式 支持数据类型 跨语言兼容 适用场景
pickle 字节流 所有 Python 对象 否(仅 Python) 内部数据持久化
json JSON 字符串 基础类型 跨语言交互
marshal 字节流 基础类型 了解即可
shelve 数据库文件 字典格式 简单键值存储

6 综合任务代码

6.1 任务 1:文本文件合并工具(按文件名顺序)

复制代码
import os

def merge_txt_files(output_filename="合并结果.txt"):
    all_files = os.listdir(".")
    txt_files = [f for f in all_files if f.endswith(".txt")]
    
    if not txt_files:
        print("当前目录没有找到任何 .txt 文件!")
        return

    txt_files.sort()
    print(f"即将合并以下文件:{txt_files}")

    with open(output_filename, "w", encoding="utf-8") as out_file:
        for file in txt_files:
            try:
                with open(file, "r", encoding="utf-8") as in_file:
                    out_file.write(f"===== 来自文件:{file} =====\n")
                    out_file.write(in_file.read())
                    out_file.write("\n\n")
                print(f"已合并:{file}")
            except Exception as e:
                print(f"读取文件 {file} 失败:{e}")

    print(f"\n✅ 合并完成!结果保存在:{output_filename}")

if __name__ == "__main__":
    merge_txt_files()

6.2 任务 2:JSON 用户信息管理系统

复制代码
import json
import os

USER_FILE = "users.json"

class UserManager:
    def __init__(self):
        self.users = []
        self.load_from_file()

    def add_user(self, user_id, name, age, phone):
        for user in self.users:
            if user["id"] == user_id:
                print("❌ 用户ID已存在!")
                return False

        new_user = {"id": user_id, "name": name, "age": age, "phone": phone}
        self.users.append(new_user)
        print("✅ 用户添加成功")
        return True

    def find_user(self, user_id):
        for user in self.users:
            if user["id"] == user_id:
                return user
        return None

    def save_to_file(self):
        with open(USER_FILE, "w", encoding="utf-8") as f:
            json.dump(self.users, f, ensure_ascii=False, indent=4)
        print("✅ 数据已保存到 users.json")

    def load_from_file(self):
        if os.path.exists(USER_FILE):
            with open(USER_FILE, "r", encoding="utf-8") as f:
                self.users = json.load(f)
            print(f"✅ 从文件加载了 {len(self.users)} 条用户数据")
        else:
            self.users = []

if __name__ == "__main__":
    um = UserManager()
    um.add_user(101, "张三", 20, "13800138000")
    um.add_user(102, "李四", 22, "13900139000")
    user = um.find_user(101)
    print("\n查询结果:", user)
    um.save_to_file()

6.3 任务 3:支持断点续传的文件复制

复制代码
import os
import json

RECORD_FILE = "copy_record.json"

class ResumableCopy:
    def __init__(self, source, target, chunk_size=1024*1024):
        self.source = source
        self.target = target
        self.chunk_size = chunk_size
        self.record = self.load_record()

    def load_record(self):
        if os.path.exists(RECORD_FILE):
            with open(RECORD_FILE) as f:
                return json.load(f)
        return {}

    def save_record(self, position):
        self.record[self.source] = position
        with open(RECORD_FILE, "w") as f:
            json.dump(self.record, f, indent=2)

    def start_copy(self):
        if not os.path.exists(self.source):
            print("❌ 源文件不存在")
            return

        total_size = os.path.getsize(self.source)
        start_pos = self.record.get(self.source, 0)

        if start_pos >= total_size:
            print("✅ 文件已完整复制,无需继续")
            if self.source in self.record:
                del self.record[self.source]
                self.save_record(0)
            return

        print(f"⏯️  从断点 {start_pos} 字节处继续复制")

        with open(self.source, "rb") as src, open(self.target, "ab") as tgt:
            src.seek(start_pos)
            while True:
                chunk = src.read(self.chunk_size)
                if not chunk:
                    break
                tgt.write(chunk)
                start_pos += len(chunk)
                self.save_record(start_pos)
                print(f"\r复制进度:{start_pos / total_size * 100:.1f}%", end="")

        print("\n✅ 复制完成!")
        if self.source in self.record:
            del self.record[self.source]
            self.save_record(0)

if __name__ == "__main__":
    copy = ResumableCopy(source="大文件.zip", target="大文件_副本.zip")
    copy.start_copy()

推荐在线正则测试工具:

1.Regex101.htm(支持语法提示、匹配结果实时预览)

2.菜鸟工具-正则表达式测试

第二部分 正则表达式

1 认识正则表达式

1.1 核心概念

  • 正则表达式(Regular Expression):简称 regex/regexp,是一种用于匹配、查找、替换文本的模式语言。

  • 核心价值:用简洁的表达式描述复杂的文本规则,高效处理字符串(匹配验证、提取筛选、替换清洗)。

  • 适用场景:表单验证(手机号、邮箱)、日志分析、数据爬虫、文本编辑器查找替换等。

1.2 正则表达式的优势

处理方式 实现逻辑 代码复杂度 灵活性 效率
普通字符串方法(in/split ()/replace ()) 逐字符比对,需手动组合逻辑 高(复杂规则需多步判断) 低(仅支持固定匹配) 简单场景高效
正则表达式 编译模式后批量匹配,支持复杂规则 低(一行表达式搞定复杂规则) 高(支持模糊匹配、动态规则) 复杂场景高效

1.3 简单示例

需求 正则表达式 匹配结果
匹配手机号(11 位数字,以 13/14/15/17/18/19 开头) ^1[3-9]\d{9}$ 匹配:13800138000,不匹配:12345678901/1380013800
匹配邮箱(以字母 / 数字开头,支持 @xx.com/xx.cn 等) ^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,6}$ 匹配:test123@qq.com,不匹配:test@.com/test#163.cn
提取文本中的所有数字 \d+ 文本:abc123def45.67 → 提取:123/45/67

2 正则表达式基础语法

正则表达式的核心是元字符(具有特殊含义的字符),通过元字符组合成匹配规则。

2.1 元字符分类与说明

2.1.1 匹配单个字符的元字符

元字符 功能 示例 匹配结果
. 匹配任意单个字符(除换行符 \n) a.b 匹配:acb/a+b/a b,不匹配:abb/a\nb
[] 匹配括号内的任意一个字符 [abc] 匹配:a/b/c
[^] 匹配括号外的任意一个字符(取反) [^abc] 匹配:d/1/!,不匹配:a/b/c
\d 匹配任意数字(等价于 [0-9]) \d 匹配:0/5/9
\D 匹配非数字(等价于 [^0-9]) \D 匹配:a/!/,不匹配:0-9
\w 匹配字母、数字、下划线(等价于 [a-zA-Z0-9_]) \w 匹配:A/3/_,不匹配:!/@/
\W 匹配非字母、数字、下划线 \W 匹配:!/@/,不匹配:a-zA-Z0-9_
\s 匹配空白字符(空格、制表符 \t、换行符 \n 等) a\sb 匹配:a b/a\tb,不匹配:ab/a_b
\S 匹配非空白字符 a\Sb 匹配:acb/a_b,不匹配:a b/a\tb
\b 单词边界(匹配单词开头 / 结尾,无实际字符) \bhello\b 匹配:hello world/say hello,不匹配:helloworld/hello_123
\B 非单词边界 \Bhello\B 匹配:helloworld/hello_123,不匹配:hello world

2.1.2 匹配数量的量词(限定前面元字符的出现次数)

量词 功能 示例 匹配结果
* 匹配前面的元字符 0 次或多次(贪婪) ab* 匹配:a/ab/abb/abbb
+ 匹配前面的元字符 1 次或多次(贪婪) ab+ 匹配:ab/abb/abbb,不匹配:a
? 匹配前面的元字符 0 次或 1 次(贪婪) ab? 匹配:a/ab,不匹配:abb
{n} 匹配前面的元字符恰好 n 次 a{3} 匹配:aaa,不匹配:aa/aaaa
{n,} 匹配前面的元字符至少 n 次(贪婪) a{2,} 匹配:aa/aaa/aaaa,不匹配:a
{n,m} 匹配前面的元字符 n~m 次(贪婪) a{2,4} 匹配:aa/aaa/aaaa,不匹配:a/aaaaa

2.1.3 匹配位置的锚定符(不匹配字符,仅匹配位置)

锚定符 功能 示例 匹配结果
^ 匹配字符串开头(多行模式下匹配每行开头) ^hello 匹配:hello world,不匹配:world hello
$ 匹配字符串结尾(多行模式下匹配每行结尾) world$ 匹配:hello world,不匹配:world hello
\A 匹配字符串绝对开头(不受多行模式影响) \Ahello 仅匹配:hello world(字符串首字符为 h)
\Z 匹配字符串绝对结尾(不受多行模式影响) world\Z 仅匹配:hello world(字符串尾字符为 d)

2.1.4 分组与逻辑运算符

符号 功能 示例 匹配结果
() 分组(将多个元字符视为一个整体,支持捕获) (ab)+ 匹配:ab/abab/ababab
` ` 逻辑或(匹配任意一个分组) `abc def` 匹配:abc/def,不匹配:abd/cde
\num 反向引用(引用第 num 个分组的匹配结果) (\w+)\s+\1 匹配:hello hello/123 123,不匹配:hello world
(?:) 非捕获分组(仅分组,不捕获结果,节省资源) (?:ab)+ 匹配:ab/abab,但无法通过 \1 引用

2.2 转义字符(\)

当需要匹配元字符本身(如 ./*/()时,需用 \ 转义:

  • 匹配 .\.(如 192\.168\.1\.1 匹配 IP 地址中的点)

  • 匹配 *\*(如 a\*b 匹配 a*b

  • 匹配 (\(`(如 `\(123\) 匹配 (123)

2.3 常用正则表达式

需求 正则表达式 说明
手机号 ^1[3-9]\d{9}$ 11 位数字,以 13/14/15/17/18/19 开头
固定电话 ^0\d{2,3}-\d{7,8}$ 格式:010-12345678 / 0571-87654321
邮箱 ^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,6}$ 支持常见域名(.com/.cn/.org 等)
身份证号(18 位) ^[1-9]\d{16}[\dXx]$ 最后一位可为数字或 X/x
IP 地址(IPv4) `^((25[0-5] 2[0-4]\d [01]?\d\d?).){3}(25[0-5] 2[0-4]\d [01]?\d\d?)$` 匹配合法 IPv4 地址
中文汉字 ^[\u4e00-\u9fa5]+$ 仅匹配纯中文(不含字母、数字、符号)
强密码 ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{8,16}$ 含大小写、数字、符号,8-16 位
URL `^(https? ftp)://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$` 匹配 http/https/ftp 网址

3 Python re 模块

Python 内置 re 模块提供正则表达式的核心操作。

3.1 re 模块函数

函数 功能 返回值 关键说明
re.match() 从字符串开头匹配 匹配对象 / None 仅匹配开头
re.search() 任意位置首次匹配 匹配对象 / None 扫描整个字符串
re.findall() 提取所有匹配结果 列表 无匹配返回空列表
re.finditer() 提取所有匹配(迭代器) 迭代器 大量结果节省内存
re.sub() 替换匹配内容 新字符串 支持字符串 / 函数替换
re.split() 按模式分割字符串 列表 支持自定义分割符
re.compile() 编译正则模式 模式对象 多次复用提高效率

3.2 匹配对象常用方法

方法 功能 示例
group() 返回整个匹配字符串 match.group() → 123
group(n) 返回第 n 个分组 match.group(1) → 2024
groups() 返回所有分组(元组) ('2024','10','01')
start() 匹配起始索引 0
end() 匹配结束索引 7
span() 匹配索引范围 (0,7)

3.3 实战示例

3.3.1 re.match () 从开头匹配

复制代码
import re
pattern = r'^1[3-9]\d{9}$'
string1 = '13800138000'
string2 = 'tel:13800138000'
print(re.match(pattern, string1).group())
print(re.match(pattern, string2))

3.3.2 re.search () 首次匹配

复制代码
pattern = r'\d+'
string = 'abc123def456'
print(re.search(pattern, string).group())

3.3.3 re.findall () 提取所有

复制代码
pattern = r'\d+\.?\d*'
string = '价格:99元,折扣:0.85,最终价格:84.15元'
print(re.findall(pattern, string))

3.3.4 re.sub () 替换内容

复制代码
# 敏感词替换
pattern = r'垃圾'
string = '这个产品真垃圾!垃圾商家!'
print(re.sub(pattern, '***', string))

# 函数替换
def add_brackets(match):
    return f'({match.group()})'
pattern = r'\d+'
string = 'a123b456c'
print(re.sub(pattern, add_brackets, string))

3.3.5 re.split () 分割字符串

复制代码
pattern = r'\s+'
string = 'hello   world\tpython\nregex'
print(re.split(pattern, string))

3.3.6 re.compile () 编译复用

复制代码
pattern = re.compile(r'[a-zA-Z]+')
string1 = '123abc456def'
string2 = '789ghi012jkl'
print(pattern.findall(string1))
print(pattern.findall(string2))

3.4 flags 模式修饰符

flags 值 功能 示例
re.I 忽略大小写 re.search(r'abc','ABC',re.I)
re.M 多行模式 ^/$ 匹配每行开头结尾
re.S 单行模式 . 匹配换行
re.X 允许注释空格 复杂正则可读性更高

示例:

复制代码
pattern = r'''
^1[3-9]
\d{9}$
'''
string = '13800138000'
print(re.match(pattern, string, re.X).group())

4 正则表达式高级用法

4.1 贪婪匹配与非贪婪匹配

  • 贪婪:尽可能多匹配(默认)

  • 非贪婪 :量词后加 ?,尽可能少匹配

表达式 文本 贪婪结果 非贪婪结果
a.*b aabcbcd aabcb -
a.*?b aabcbcd - aab

示例:

复制代码
html = '<div>正则</div><div>实战</div>'
greedy = r'<div.*</div>'
non_greedy = r'<div.*?</div>'
print(re.findall(greedy, html))
print(re.findall(non_greedy, html))

4.2 分组与反向引用

4.2.1 捕获分组

复制代码
pattern = r'(\d{4})-(\d{2})-(\d{2})'
string = '2024-10-01'
res = re.search(pattern, string)
print(res.group(1), res.group(2), res.group(3))

4.2.2 反向引用

复制代码
pattern = r'(\w+)\s+\1'
print(re.search(pattern, 'hello hello').group())

4.2.3 非捕获分组

复制代码
pattern = r'(?:ab)+'
print(re.search(pattern, 'abab').group())

4.3 零宽断言(位置匹配)

断言 功能 示例
(?=pattern) 后面满足 a(?=b)
(?!pattern) 后面不满足 a(?!b)
(?<=pattern) 前面满足 (?<=a)b
(?<!pattern) 前面不满足 (?<!a)b

示例:

复制代码
pattern = r'\d+\.?\d*(?=元)'
string = '价格:99元,折扣价:84.5元'
print(re.findall(pattern, string))

5 常见场景案例

5.1 表单验证(手机号 + 邮箱)

复制代码
import re
def validate_phone(phone):
    return bool(re.match(r'^1[3-9]\d{9}$', phone))
def validate_email(email):
    return bool(re.match(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+\.[a-zA-Z]{2,6}$', email))

5.2 日志分析(提取 IP、时间)

复制代码
log = '''192.168.1.1 - - [01/Oct/2024:12:00:00 +0800] "GET /index.html" 200'''
pattern = r'(\d+\.\d+\.\d+\.\d+).*?\[([^\]]+)\] "(\w+) ([^"]+)" (\d+)'
for res in re.findall(pattern, log):
    print(f"IP:{res[0]}, 时间:{res[1]}")

5.3 文本清洗(去 HTML、多余空格)

复制代码
def clean_text(text):
    text = re.sub(r'<[^>]+>', '', text)
    text = re.sub(r'\s+', ' ', text).strip()
    return text

5.4 提取图片 URL

复制代码
html = '<img src="https://example.com/img1.jpg">'
pattern = r'<img.*?src="([^"]+)"'
print(re.findall(pattern, html))

6 正则表达式常见误区

6.1 误区 1:忘记转义元字符

  • 错误:192.168.1.1

  • 正确:192\.168\.1\.1

6.2 误区 2:混淆 ^/$ 与 \A/\Z

  • ^/$ 受多行模式影响

  • \A/\Z 始终匹配整个字符串

6.3 误区 3:过度使用贪婪匹配

  • 提取标签优先使用 .*?

6.4 误区 4:忽略大小写与换行

  • 忽略大小写:re.I

  • 匹配换行:re.S

6.5 性能优化

  • 多次使用:re.compile()

  • 复杂分组:非捕获分组 (?:)

  • 大数据:re.finditer()

7 任务代码

7.1 任务 1:身份证验证 + 提取生日

复制代码
import re
def check_id_card(id_str):
    pattern = r'^[1-9]\d{16}[\dXx]$'
    if not re.fullmatch(pattern, id_str):
        return False, "格式错误"
    birth = id_str[6:14]
    return True, f"{birth[:4]}-{birth[4:6]}-{birth[6:8]}"

7.2 任务 2:提取 URL 域名

复制代码
import re
def get_domain_from_url(url):
    res = re.search(r'https?://([^/]+)', url)
    return res.group(1) if res else None

7.3 任务 3:清洗纯中文文本

复制代码
import re
def clean_chinese_text(text):
    text = re.sub(r'<[^>]+>', '', text)
    return re.sub(r'[^\u4e00-\u9fa5,。!?;:""''()【】]', '', text).strip()

7.4 任务 4:手机号脱敏

复制代码
import re
def mask_phone(phone):
    return re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', phone)

第三部分 Python进阶

1 文件操作进阶

文件操作是 Python 数据处理与项目开发的基础,进阶内容聚焦 非文本文件处理、大文件高效处理、路径灵活适配 三大核心场景,解决基础文件操作的局限性。

1.1 二进制文件读写

适用于图片、视频、音频、压缩包等非文本文件,核心是通过二进制模式(rb/wb/ab)操作数据,保留文件原始字节信息。

1.1.1 核心模式说明

模式 功能 适用场景
rb 二进制读模式 读取图片、视频等非文本文件
wb 二进制写模式(覆盖) 保存图片、生成二进制文件
ab 二进制追加模式 向二进制文件追加内容

1.1.2 实战案例:通用文件复制

复制代码
"""
二进制文件复制:支持图片、视频、音频等所有文件类型
核心:按字节读取和写入,保留文件原始数据
"""
def copy_binary_file(src_path, dst_path):
    try:
        with open(src_path, "rb") as f_in, open(dst_path, "wb") as f_out:
            data = f_in.read()
            f_out.write(data)
        print(f"文件复制成功:{src_path} → {dst_path}")
    except FileNotFoundError:
        print(f"错误:源文件 {src_path} 不存在")
    except PermissionError:
        print(f"错误:无权限访问文件")
    except Exception as e:
        print(f"文件复制失败:{str(e)}")

# 调用
copy_binary_file("input.jpg", "output.jpg")

1.2 大文件分块处理

文件体积过大(1GB 以上)时,一次性读取会导致内存溢出,分块处理实现逐块读取 - 逐块写入,高效复用内存。

1.2.1 实战案例:大文件分块复制

复制代码
"""
大文件分块复制:适用于 GB 级文件,避免内存溢出
chunk_size:分块大小,1024*1024 = 1MB
"""
def copy_large_file(src_path, dst_path, chunk_size=1024*1024):
    try:
        with open(src_path, "rb") as f_in, open(dst_path, "wb") as f_out:
            while True:
                chunk = f_in.read(chunk_size)
                if not chunk:
                    break
                f_out.write(chunk)
        print(f"大文件复制成功:{src_path} → {dst_path}")
    except Exception as e:
        print(f"大文件复制失败:{str(e)}")

# 调用
copy_large_file("large_video.mp4", "copy_video.mp4")

1.2.2 分块大小选型建议

文件大小 推荐分块大小 内存占用
100MB 以内 1MB 约 1MB
1GB~5GB 4MB~8MB 约 4MB~8MB
5GB 以上 16MB 约 16MB

1.3 路径处理与目录遍历

通过 os 模块实现路径动态拼接、目录遍历,适配 Windows/Linux/Mac 系统。

1.3.1 路径函数

函数 功能
os.path.join() 动态拼接路径
os.path.exists() 判断路径是否存在
os.makedirs() 创建目录
os.walk() 递归遍历目录

1.3.2 实战案例 1:动态路径与目录创建

复制代码
import os

base_dir = "project_data"
log_dir = os.path.join(base_dir, "logs")
data_file = os.path.join(base_dir, "user_data.txt")

if not os.path.exists(log_dir):
    os.makedirs(log_dir)
    print(f"目录创建成功:{log_dir}")

with open(data_file, "w", encoding="utf-8") as f:
    f.write("用户数据:动态路径测试")

1.3.3 实战案例 2:递归查找 .py 文件

复制代码
import os

def find_py_files(root_dir):
    py_files = []
    for root, dirs, files in os.walk(root_dir):
        for file in files:
            if file.endswith(".py"):
                full_path = os.path.join(root, file)
                py_files.append(full_path)
    return py_files

# 调用
py_list = find_py_files(".")
for file in py_list:
    print(file)

2 异常处理进阶

聚焦 自定义异常、多异常精准捕获、异常链追溯,适配复杂业务错误处理。

2.1 自定义异常类

继承 Exception 实现业务专属异常,提升错误信息可读性。

2.1.1 定义自定义异常

复制代码
class BusinessError(Exception):
    """业务逻辑异常"""
    def __init__(self, code, message):
        self.code = code
        self.message = message
        super().__init__(f"错误码:{code},错误信息:{message}")

class DataFormatError(BusinessError):
    """数据格式异常"""
    def __init__(self, field):
        super().__init__(400, f"数据格式错误:字段 {field} 不合法")

2.1.2 抛出与捕获

复制代码
def process_user_data(data):
    if not data:
        raise BusinessError(400, "用户数据不能为空")
    if "name" not in data:
        raise DataFormatError("name")
    return f"处理成功:{data['name']}"

try:
    process_user_data({"age": 18})
except DataFormatError as e:
    print(f"数据异常:{e.message}")
except BusinessError as e:
    print(f"业务异常:{e.message}")

2.2 多异常精准捕获

遵循 从具体到通用 原则,避免异常覆盖。

复制代码
try:
    data = int(input("请输入数字:"))
    result = 10 / data
except ValueError:
    print("错误:请输入有效整数")
except ZeroDivisionError:
    print("错误:除数不能为零")
except Exception as e:
    print(f"未知错误:{e}")
else:
    print(f"结果:{result}")
finally:
    print("执行完毕")

2.3 异常链处理(Python 3.11+)

raise ... from ... 保留异常上下文,快速定位根源。

复制代码
def read_config(file_path):
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            return f.read()
    except FileNotFoundError as e:
        e.add_note(f"路径:{file_path}")
        raise BusinessError(500, "配置文件读取失败") from e

3 模块化开发进阶

核心:高内聚、低耦合,解决大型项目模块混乱、依赖冲突问题。

3.1 包的导入优化

通过 __init__.py 控制导入行为,简化调用。

3.1.1 init.py 配置

复制代码
# my_package/__init__.py
from .module1 import func1, Class1
from .module2 import func2
from .utils.helper import format_data

__all__ = ["func1", "Class1", "func2", "format_data"]
PACKAGE_VERSION = "1.0.0"

3.1.2 简化导入效果

复制代码
# 优化后
from my_package import func1, format_data

3.2 绝对导入与相对导入

导入方式 优点 适用场景
绝对导入 路径清晰、跨包支持 大型多包项目
相对导入 无需硬编码包名 单包内部交互
复制代码
# 绝对导入
from package_a.module_a import func_a

# 相对导入
from .module1 import func1
from ..module1 import func1

3.3 模块依赖管理

使用 requirements.txt 管理第三方依赖。

复制代码
# 导出依赖
pip freeze > requirements.txt

# 安装依赖
pip install -r requirements.txt

3.4 跨文件数据共享

优先使用配置模块 / 配置类,避免全局变量。

3.4.1 配置模块(config.py

复制代码
APP_NAME = "实战项目"
DB_CONFIG = {"host": "127.0.0.1", "port": 3306}

3.4.2 配置类(面向对象)

复制代码
class AppConfig:
    def __init__(self):
        self.app_name = "实战项目"
        self.debug = True

config = AppConfig()

4 综合实战:文件处理工具包

4.1 项目结构

复制代码
file_toolkit/
├── __init__.py
├── file_operate.py
├── path_utils.py
├── config_reader.py
├── logger.py
└── config.json

4.2 核心模块代码

4.2.1 日志模块(logger.py

复制代码
import logging, os
from datetime import datetime

def setup_logger():
    log_dir = "logs"
    os.makedirs(log_dir, exist_ok=True)
    log_file = os.path.join(log_dir, f"{datetime.now():%Y-%m-%d}.log")
    
    formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
    logger = logging.getLogger("file_toolkit")
    logger.addHandler(logging.FileHandler(log_file, encoding="utf-8"))
    logger.addHandler(logging.StreamHandler())
    return logger

logger = setup_logger()

4.2.2 文件操作模块(file_operate.py)

复制代码
import os
from .logger import logger

def copy_file(src_path, dst_path, chunk_size=1024*1024):
    try:
        with open(src_path, "rb") as f_in, open(dst_path, "wb") as f_out:
            while chunk := f_in.read(chunk_size):
                f_out.write(chunk)
        logger.info(f"复制成功:{src_path}")
        return True
    except Exception as e:
        logger.error(f"复制失败:{e}")
        return False

4.2.3 路径工具模块(path_utils.py)

复制代码
import os
from .logger import logger

def find_files_by_suffix(root_dir, suffix_list):
    match_files = []
    for root, _, files in os.walk(root_dir):
        for f in files:
            if f.endswith(tuple(suffix_list)):
                match_files.append(os.path.join(root, f))
    return match_files

4.2.4 配置读取模块(config_reader.py)

复制代码
import json, os
from .logger import logger

def read_json_config(file_path):
    with open(file_path, "r", encoding="utf-8") as f:
        return json.load(f)

4.2.5 包初始化(init.py)

复制代码
from .file_operate import copy_file
from .path_utils import find_files_by_suffix
from .config_reader import read_json_config
from .logger import logger

__version__ = "1.0.0"
__all__ = ["copy_file", "find_files_by_suffix", "read_json_config", "logger"]

4.3 项目使用示例

复制代码
from file_toolkit import copy_file, find_files_by_suffix, read_json_config

copy_file("large.mp4", "backup/large.mp4")
files = find_files_by_suffix(".", [".py", ".json"])
config = read_json_config("config.json")
相关推荐
chushiyunen2 小时前
milvus笔记、常用表结构
笔记·算法·milvus
Lyyaoo.2 小时前
【JAVA基础面经】== 和 equals() 的区别
java·开发语言·jvm
liliangcsdn2 小时前
ChromaDB距离计算公式示例
人工智能·算法·机器学习
人道领域2 小时前
【LeetCode刷题日记】242.字母异位词
算法·leetcode·职场和发展
lifallen2 小时前
Flink Agent:RunnerContext 注入与装配演进分析
java·大数据·人工智能·语言模型·flink
爱丽_2 小时前
Tomcat 从 Socket 到 Servlet:机制主线、参数调优与线上排障(实战)
java·servlet·tomcat
小江的记录本2 小时前
【JEECG Boot】 JEECG Boot——数据字典管理 系统性知识体系全解析
java·前端·spring boot·后端·spring·spring cloud·mybatis
卖男孩的小火柴.2 小时前
java内置方法总结及基础算法
java·算法
旖-旎2 小时前
链表(两两交换链表中的节点)(2)
数据结构·c++·学习·算法·链表·力控