--- tid: 32dcdi title: String Tutorial --- # Lab 1.2 - Python 字符串处理实战 (date: 2025-11-15) 这个教程通过实际案例展示了Python字符串处理的各个方面,从基础操作到高级应用,帮助你掌握在实际项目中处理字符串的技巧。 ## 案例1:处理用户消息中的引号问题 [step 1] ### 问题场景 某开发人员在开发聊天机器人时,遇到了字符串输出不正确的问题。用户消息中包含各种引号,导致程序无法正常运行。 ### 问题代码 ```python # 开发人员编写的代码出现了语法错误,你能找出问题并修复吗? user_message1 = 'I'm learning Python, it's awesome!' user_message2 = 'He said: "Python's syntax is clean"' complex_message = `User said: "I can't believe Python's simplicity!"` print(user_message1) print(user_message2) ``` ### 解决方案 提示: 通过以下方法可以修复代码中的引号问题: ```python # 方法1:使用转义字符 user_message1 = 'I\'m learning Python, it\'s awesome!' # 方法2:混合使用引号 user_message1 = "I'm learning Python, it's awesome!" # 方法3:使用三引号处理复杂情况 complex_message = """User said: "I can't believe Python's simplicity!" """ print(complex_message) ``` 要求:用同样的方法完成 `user_message2` 的处理。 ``````{only} show_answer ``` user_message2 = 'He said: "Python\'s syntax is clean"' ``` `````` ## 案例2:文件路径处理实战 [step 2] ### 场景描述 学习如何正确处理文件路径,避免转义字符带来的问题。 ### 前置引导:简单文件读取 准备: 先在当前目录创建一个名为 simple.txt 的文件,内容随意 先让我们先学习如何正确读取当前目录下的文件: ```python # 用 python 打开 simple.txt 并读入其内容 file_path = "simple.txt" print(f"尝试访问文件: {file_path}") with open(file_path, 'r') as file: content = file.read() print("文件内容:", content) ``` ### 问题引入:转义字符带来的问题 现在,请先在 C:\new_folder\ 目录下手动创建一个名为 `test.txt` 的文本文件,内容和刚才的 simple.txt 相同。然后,读取这个文件: ```python # 再次读取 file_path = "C:\new_folder\test.txt" print(f"尝试访问文件: {file_path}") # 这会报错! with open(file_path, 'r') as file: content = file.read() print("文件内容:", content) ``` ### 解决方案 观察输出结果,你会发现路径显示异常,这是因为 \n 和 \t 被当作转义字符处理了。正确解法: ```python # 方法1:使用原始字符串(推荐) file_path = r"C:..." print(f"方法1 - 原始字符串: {file_path}") # 方法2:使用正斜杠(跨平台兼容) file_path = "C:/new_folder..." print(f"方法2 - 正斜杠路径: {file_path}") # 方法3:双重转义 file_path = "C:\\..." print(f"方法3 - 双重转义: {file_path}") # 现在可以安全使用了 with open(file_path, 'r') as file: content = file.read() print("文件内容:", content) print("文件读取成功!") ``` 要求: 请补全 `...` 处的代码,使其正确 ``````{only} show_answer ``` file_path = r"C:\new_folder\test.txt" file_path = "C:/new_folder/test.txt" file_path = "C:\\new_folder\\test.txt" ``` `````` ## 案例3:命令行帮助文档格式化 [step 3] ### 场景描述 为你的Python工具创建美观的命令行帮助文档。当用户输入错误命令或请求帮助时,显示格式化的使用说明。 ### 前置引导 创建格式化的帮助信息: ``` Usage: mytool [command] -h, --help 显示帮助信息 -v, --version 显示版本信息 -c CONFIG 指定配置文件 ``` 原始实现方法: ```python # 方法1:基础版本 - 多次单行打印(不推荐) print("Usage: mytool [command]") print(" -h, --help 显示帮助信息") print(" -v, --version 显示版本信息") print(" -c CONFIG 指定配置文件") ``` 上面的写法有很多缺点: - 代码冗长,重复调用 `print()` - 难以维护,修改时需要逐行调整 - 无法将帮助文本作为变量复用 - 格式控制不够灵活 ### 解决方案 要求程序文件中将这个多行字符串放在变量中,通过打印该变量来显示精美的格式化帮助信息。 ```python # 方法2:使用三引号字符串(推荐) help_text = """\ Usage: mytool [command] -h, --help 显示帮助信息 ... ... """ print(help_text) ``` 要求: 请补全 `...` 处的代码,使其正确 ```python # 方法3:使用字符串连接(灵活组合) usage = "Usage: mytool [command]\n" options = [ " -h, --help 显示帮助信息", " -v, --version 显示版本信息", " -c CONFIG 指定配置文件" ] full_help = usage + "\n\n".join(options) print(full_help) # 对比说明: # - 方法1:代码冗长,难以维护 # - 方法2:简洁清晰,适合固定内容 # - 方法3:灵活组合,适合动态生成 ``` 要求:修改上面的代码,使其正确 ``````{only} show_answer ```python # 方法2:使用三引号字符串(推荐) help_text = """\ Usage: mytool [command] -h, --help 显示帮助信息 -v, --version 显示版本信息 -c CONFIG 指定配置文件 """ ``` ```python # 方法3:使用字符串连接(灵活组合) usage = "Usage: mytool [command]\n" options = [ " -h, --help 显示帮助信息", " -v, --version 显示版本信息", " -c CONFIG 指定配置文件" ] ``` `````` ## 案例4:用户数据清洗和格式化 [step 4] ### 场景描述 你收到了一批用户数据,需要进行清洗和标准化处理,以便在系统中统一使用。 ```python # 原始数据 raw_users = [ " john DOE ", "ALICE SMITH ", " bob wilson", "Mary-Jane O'Conner" ] ``` ### 前置引导 原始数据存在以下问题: - 首尾空格不一致 - 大小写格式混乱 - 姓名分隔符不统一 需要完成以下清洗任务: 1. 去除首尾空格 2. 将姓名格式化为"首字母大写" 3. 用下划线连接名和姓 ### 预期结果 ``` 原始数据: [' john DOE ', 'ALICE SMITH ', ' bob wilson', "Mary-Jane O'Conner"] 清洗后: ['John_Doe', 'Alice_Smith', 'Bob_Wilson', 'Mary_Jane_O_Conner'] ``` ### 解决方案 方法1:使用函数(推荐) ```python def clean_user_data(users): cleaned = [] for user in users: # 去除空格并分割姓名 clean_name = user.strip() # 首字母大写 clean_name = clean_name.title() # 用下划线替换空格和连字符 clean_name = clean_name.replace(' ', '_').replace('-', '_') cleaned.append(clean_name) return cleaned # 测试清洗函数 cleaned_users = clean_user_data(raw_users) print("清洗后的用户数据:") for user in cleaned_users: print(f" - {user}") ``` 方法2:使用列表推导式(简洁版本) ```python cleaned_users_v2 = [ user.strip().upper().replace(' ', '_')... for user in raw_users ] print("\n列表推导式版本:") for user in cleaned_users_v2: print(f" - {user}") ``` 要求:请补全 `...` 处的代码,使其正确 ``````{only} show_answer ```python cleaned_users_v2 = [ user.strip().title().replace(' ', '_').replace('-', '_') for user in raw_users ] print("\n列表推导式版本:") for user in cleaned_users_v2: print(f" - {user}") ``` `````` - 两种方法都能达到相同的清洗效果 - 函数版本适合复杂逻辑,列表推导式适合简单转换 ## 案例5:日志消息解析 [step 5] ### 场景描述 你需要从系统日志中提取关键信息,用于监控系统运行状态。 ### 前置引导 日志格式遵循标准结构: ``` # [级别] 时间戳 - 消息内容 log_entries = [ "[ERROR] 2024-09-29 17:12:22 - Database connection failed", "[INFO] 2024-09-29 17:12:25 - User login successful", "[WARN] 2024-09-29 17:12:30 - High memory usage detected" ] ``` 需要从每条日志中提取三个关键信息: - 日志级别(ERROR/INFO/WARN) - 时间戳 - 消息内容 ### 预期结果 ``` 日志: [ERROR] 2024-09-29 17:12:22 - Database connection failed 提取结果: 级别=ERROR, 时间=2024-09-29 17:12:22, 消息=Database connection failed 日志: [INFO] 2024-09-29 17:12:25 - User login successful 提取结果: 级别=INFO, 时间=2024-09-29 17:12:25, 消息=User login successful 日志: [WARN] 2024-09-29 17:12:30 - High memory usage detected 提取结果: 级别=WARN, 时间=2024-09-29 17:12:30, 消息=High memory usage detected ``` ### 解决方案 方法1:使用字符串查找和分割(不使用字典) ```python def parse_log_entry_simple(entry): # 查找日志级别结束位置 level_end = entry.find(']') level = entry[...:level_end].strip() # 查找时间戳结束位置 time_start = level_end + ... time_end = entry.find(' - ') timestamp = entry[time_start:time_end].strip() # 提取消息内容 message = entry[time_end + ...:].strip() # 返回三个独立的变量 return level, timestamp, message # 解析并显示所有日志 print("日志解析结果:") for entry in log_entries: level, timestamp, message = parse_log_entry_simple(entry) print(f"日志: {entry}") print(f"提取结果: 级别={level}, 时间={timestamp}, 消息={message}") ``` ``````{only} show_answer ```python def parse_log_entry_simple(entry): # 查找日志级别结束位置 level_end = entry.find(']') level = entry[1:level_end].strip() # 查找时间戳结束位置 time_start = level_end + 2 time_end = entry.find(' - ') timestamp = entry[time_start:time_end].strip() # 提取消息内容 message = entry[time_end + 3:].strip() # 返回三个独立的变量 return level, timestamp, message # 解析并显示所有日志 print("日志解析结果:") for entry in log_entries: level, timestamp, message = parse_log_entry_simple(entry) print(f"日志: {entry}") print(f"提取结果: 级别={level}, 时间={timestamp}, 消息={message}") ``` `````` 方法2:使用字典(进阶版本) ```python def parse_log_entry_dict(entry): level_end = entry.find(']') level = entry[1:level_end].strip() time_start = level_end + 2 time_end = entry.find(' - ') timestamp = entry[time_start:time_end].strip() message = entry[time_end + 3:].strip() return { 'level': level, 'timestamp': timestamp, 'message': ... } print("\n使用字典版本:") for entry in log_entries: parsed = parse_log_entry_dict(entry) print(f"级别: {parsed['...']}") print(f"时间: {...['timestamp']}") print(f"消息: {parsed['...']}") print("-" * 30) ``` 要求: 请补全 `...` 处的代码,使其正确 ``````{only} show_answer ```python def parse_log_entry_dict(entry): level_end = entry.find(']') level = entry[1:level_end].strip() time_start = level_end + 2 time_end = entry.find(' - ') timestamp = entry[time_start:time_end].strip() message = entry[time_end + 3:].strip() return { 'level': level, 'timestamp': timestamp, 'message': message } print("\n使用字典版本:") for entry in log_entries: parsed = parse_log_entry_dict(entry) print(f"级别: {parsed['level']}") print(f"时间: {parsed['timestamp']}") print(f"消息: {parsed['message']}") print("-" * 30) ``` `````` 两种方法都能正确解析日志, 简单版本适合初学者,字典版本适合结构化数据 ## 案例6:动态消息模板 [step 6] ### 场景描述 创建个性化的用户欢迎消息和邮件模板,根据用户信息动态生成内容。 ### 前置引导 用户数据包含姓名、等级、加入日期和积分: ```python user_data = { 'name': '张三', 'level': 'VIP', 'join_date': '2024-09-29', 'points': 1500 } ``` 需要生成格式化的欢迎消息,包含所有用户信息。 ### 预期结果 ``` 🎉 欢迎 张三! 感谢您于 2024-09-29 加入我们。 您的会员等级: VIP 当前积分: 1500 祝您使用愉快! ``` ### 解决方案 方法1:f-string(推荐) ```python welcome_message = f""" 🎉 欢迎 {user_data['name']}! 感谢您于 {user_data['join_date']} 加入我们。 您的会员等级: {user_data['level']} 当前积分: {user_data['points']} 祝您使用愉快! """ print("f-string 版本:") print(welcome_message) ``` 方法2:str.format() ```python template = """ 🎉 欢迎 {name}! 感谢您于 {join_date} 加入我们。 您的会员等级: {level} 当前积分: {points} 祝您使用愉快! """ print("format() 版本:") print(template.format(**user_data)) ``` 方法3:字符串模板 ```python from string import Template tmpl = Template(""" 🎉 欢迎 $name! 感谢您于 $join_date 加入我们。 您的会员等级: $level 当前积分: $points 祝您使用愉快! """) print("Template 版本:") print(tmpl.substitute(user_data)) ``` 要求: 理换另一组数据,重新打印结果: ``` user_data = { 'name': '换成你自己的名字', 'level': 'SVIP', 'join_date': '2025-09-29', 'points': 3000 } ``` 语法小结: - f-string 最简洁直观,适合现代Python开发 - str.format() 适合模板复用场景 - Template 提供最简单的变量替换语法 ## 案例7:文本对齐和表格生成 [step 7] ### 场景描述 生成格式化的产品价格表,确保各列对齐显示。 ### 前置引导 产品数据包含名称、价格和分类: ```python products = [ ("笔记本电脑", 5999, "电子"), ("Python编程书", 89, "图书"), ("无线鼠标", 159, "电子"), ("咖啡杯", 45, "生活") ] ``` 需要生成对齐的表格,各列根据内容自动调整宽度。 ### 预期结果 ``` 产品名称 | 价格 | 分类 ---------------------------- 笔记本电脑 | 5999 | 电子 Python编程书 | 89 | 图书 无线鼠标 | 159 | 电子 咖啡杯 | 45 | 生活 ``` ### 解决方案 方法1:使用字符串格式化 ```python def create_product_table(products): # 计算每列的最大宽度 name_width = max(len(product[0]) for product in products) price_width = max(len(str(product[1])) for product in products) category_width = max(len(product[2]) for product in products) # 表头 header = f"{'产品名称':>{name_width}} | {'价格':^{price_width}} | {'分类':<{category_width}}" separator = "-" * len(header) # 构建表格 table = [header, separator] for name, price, category in products: row = f"{name:>{name_width}} | {price:^{price_width}} | {category:<{category_width}}" table.append(row) return "\n".join(table) print("产品价格表:") print(create_product_table(products)) ``` 要求: 将上面的价格换算成美元,且小数点后保留两位,重新输出此表,要求同样整齐和美观显示 - 使用字符串格式化实现列对齐 - 左对齐产品名称和分类,右对齐价格 - 自动计算列宽确保美观显示 ## 案例8:正则表达式实战 - 提取联系信息 [step 8] ### 场景描述 从文本中提取电话号码和邮箱地址,用于自动化处理联系信息。 ### 前置引导 文本中包含多种格式的联系信息: ```python text = """ 请联系我们: 电话: 138-1234-5678 备用电话: (086) 028-8765-4321 邮箱: contact@company.com 客服邮箱: support@company.cn 紧急联系: 13987654321 """ ``` 需要提取: - 手机号码(11位数字) - 带格式的电话号码(xxx-xxxx-xxxx) - 邮箱地址 ### 预期结果 ``` 手机号码: ['13987654321'] 格式电话: ['138-1234-5678', '028-8765-4321'] 邮箱地址: ['contact@company.com', 'support@company.cn'] ``` ### 解决方案 方法1:使用正则表达式提取 ```python import re def extract_contact_info(text): # 提取手机号码 phone_pattern = r'1[3-9]\d{9}' phones = re.findall(phone_pattern, text) # 提取带格式的电话 formatted_phone_pattern = r'\d{3}-\d{4}-\d{4}' formatted_phones = re.findall(formatted_phone_pattern, text) # 提取邮箱 email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' emails = re.findall(email_pattern, text) return { 'phones': phones, 'formatted_phones': formatted_phones, 'emails': emails } # 提取信息 contact_info = extract_contact_info(text) print("提取的联系信息:") print(f"手机号码: {contact_info['phones']}") print(f"格式电话: {contact_info['formatted_phones']}") print(f"邮箱地址: {contact_info['emails']}") ``` - 使用正则表达式匹配特定模式 - 手机号码:1开头,11位数字 - 格式电话:xxx-xxxx-xxxx格式 - 邮箱地址:标准邮箱格式 要求: 在原始数据中加入QQ号码,重新提取,并输出结果 ## 综合练习:构建简单的报告生成器 [step 9] ### 场景描述 结合所有学到的知识,创建一个灵活的报告生成器,支持不同对齐方式。 ### 前置引导 销售数据包含产品名称和价格: ```python sales_data = [ ("产品A", "¥1,200"), ("产品B", "¥3,450"), ("产品C", "¥890"), ("总计", "¥5,540") ] ``` 需要生成格式化的报告,支持左对齐、居中、右对齐三种方式。 ### 预期结果 ``` 销售报告 ===================== 产品A : ¥1,200 产品B : ¥3,450 产品C : ¥890 总计 : ¥5,540 ``` ### 解决方案 方法1:通用报告生成器 ```python def generate_report(title, data, align='left'): """ 生成格式化的报告 参数: title - 报告标题 data - 数据列表,每个元素为(标签, 值) align - 对齐方式: 'left', 'center', 'right' """ # 计算最大宽度 label_width = max(len(str(item[0])) for item in data) value_width = max(len(str(item[1])) for item in data) # 标题 if align == 'center': title_line = title.center(label_width + value_width + 3) elif align == 'right': title_line = title.rjust(label_width + value_width + 3) else: title_line = title.ljust(label_width + value_width + 3) # 构建报告 report = [title_line, "=" * (label_width + value_width + 3)] for label, value in data: if align == 'center': label_str = label.center(label_width) value_str = str(value).center(value_width) elif align == 'right': ... ... else: label_str = label.ljust(label_width) value_str = str(value).ljust(value_width) report.append(f"{label_str} : {value_str}") return "\n".join(report) # 使用报告生成器 print(generate_report("销售报告", sales_data, align='center')) ``` 要求: 修改代码,使其支持自动计算列宽,确保美观显示 - 结合字符串格式化、对齐、宽度计算等技巧 - 支持多种对齐方式,灵活适应不同需求 - 自动计算列宽,确保美观显示 ``````{only} show_answer ```python def generate_report(title, data, align='left'): """ 生成格式化的报告 参数: title - 报告标题 data - 数据列表,每个元素为(标签, 值) align - 对齐方式: 'left', 'center', 'right' """ # 计算最大宽度 label_width = max(len(str(item[0])) for item in data) value_width = max(len(str(item[1])) for item in data) # 标题 if align == 'center': title_line = title.center(label_width + value_width + 3) elif align == 'right': title_line = title.rjust(label_width + value_width + 3) else: title_line = title.ljust(label_width + value_width + 3) # 构建报告 report = [title_line, "=" * (label_width + value_width + 3)] for label, value in data: if align == 'center': label_str = label.center(label_width) value_str = str(value).center(value_width) elif align == 'right': label_str = label.rjust(label_width) value_str = str(value).rjust(value_width) else: label_str = label.ljust(label_width) value_str = str(value).ljust(value_width) report.append(f"{label_str} : {value_str}") return "\n".join(report) # 使用报告生成器 print(generate_report("销售报告", sales_data, align='center')) ``` ``````