Lab 1.2 - Python 字符串处理实战¶
(date: 2025-11-15)
这个教程通过实际案例展示了Python字符串处理的各个方面,从基础操作到高级应用,帮助你掌握在实际项目中处理字符串的技巧。
案例1:处理用户消息中的引号问题¶
[step 1]
问题场景¶
某开发人员在开发聊天机器人时,遇到了字符串输出不正确的问题。用户消息中包含各种引号,导致程序无法正常运行。
问题代码¶
# 开发人员编写的代码出现了语法错误,你能找出问题并修复吗?
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)
解决方案¶
提示: 通过以下方法可以修复代码中的引号问题:
# 方法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 的处理。
案例2:文件路径处理实战¶
[step 2]
场景描述¶
学习如何正确处理文件路径,避免转义字符带来的问题。
前置引导:简单文件读取¶
准备: 先在当前目录创建一个名为 simple.txt 的文件,内容随意
先让我们先学习如何正确读取当前目录下的文件:
# 用 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 相同。然后,读取这个文件:
# 再次读取
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 被当作转义字符处理了。正确解法:
# 方法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("文件读取成功!")
要求: 请补全 ... 处的代码,使其正确
案例3:命令行帮助文档格式化¶
[step 3]
场景描述¶
为你的Python工具创建美观的命令行帮助文档。当用户输入错误命令或请求帮助时,显示格式化的使用说明。
前置引导¶
创建格式化的帮助信息:
Usage: mytool [command]
-h, --help 显示帮助信息
-v, --version 显示版本信息
-c CONFIG 指定配置文件
原始实现方法:
# 方法1:基础版本 - 多次单行打印(不推荐)
print("Usage: mytool [command]")
print(" -h, --help 显示帮助信息")
print(" -v, --version 显示版本信息")
print(" -c CONFIG 指定配置文件")
上面的写法有很多缺点:
代码冗长,重复调用
print()难以维护,修改时需要逐行调整
无法将帮助文本作为变量复用
格式控制不够灵活
解决方案¶
要求程序文件中将这个多行字符串放在变量中,通过打印该变量来显示精美的格式化帮助信息。
# 方法2:使用三引号字符串(推荐)
help_text = """\
Usage: mytool [command]
-h, --help 显示帮助信息
...
...
"""
print(help_text)
要求: 请补全 ... 处的代码,使其正确
# 方法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:灵活组合,适合动态生成
要求:修改上面的代码,使其正确
案例4:用户数据清洗和格式化¶
[step 4]
场景描述¶
你收到了一批用户数据,需要进行清洗和标准化处理,以便在系统中统一使用。
# 原始数据
raw_users = [
" john DOE ",
"ALICE SMITH ",
" bob wilson",
"Mary-Jane O'Conner"
]
前置引导¶
原始数据存在以下问题:
首尾空格不一致
大小写格式混乱
姓名分隔符不统一
需要完成以下清洗任务:
去除首尾空格
将姓名格式化为"首字母大写"
用下划线连接名和姓
预期结果¶
原始数据: [' john DOE ', 'ALICE SMITH ', ' bob wilson', "Mary-Jane O'Conner"]
清洗后: ['John_Doe', 'Alice_Smith', 'Bob_Wilson', 'Mary_Jane_O_Conner']
解决方案¶
方法1:使用函数(推荐)
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:使用列表推导式(简洁版本)
cleaned_users_v2 = [
user.strip().upper().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:使用字符串查找和分割(不使用字典)
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}")
方法2:使用字典(进阶版本)
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)
要求: 请补全 ... 处的代码,使其正确
两种方法都能正确解析日志, 简单版本适合初学者,字典版本适合结构化数据
案例6:动态消息模板¶
[step 6]
场景描述¶
创建个性化的用户欢迎消息和邮件模板,根据用户信息动态生成内容。
前置引导¶
用户数据包含姓名、等级、加入日期和积分:
user_data = {
'name': '张三',
'level': 'VIP',
'join_date': '2024-09-29',
'points': 1500
}
需要生成格式化的欢迎消息,包含所有用户信息。
预期结果¶
🎉 欢迎 张三!
感谢您于 2024-09-29 加入我们。
您的会员等级: VIP
当前积分: 1500
祝您使用愉快!
解决方案¶
方法1:f-string(推荐)
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()
template = """
🎉 欢迎 {name}!
感谢您于 {join_date} 加入我们。
您的会员等级: {level}
当前积分: {points}
祝您使用愉快!
"""
print("format() 版本:")
print(template.format(**user_data))
方法3:字符串模板
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]
场景描述¶
生成格式化的产品价格表,确保各列对齐显示。
前置引导¶
产品数据包含名称、价格和分类:
products = [
("笔记本电脑", 5999, "电子"),
("Python编程书", 89, "图书"),
("无线鼠标", 159, "电子"),
("咖啡杯", 45, "生活")
]
需要生成对齐的表格,各列根据内容自动调整宽度。
预期结果¶
产品名称 | 价格 | 分类
----------------------------
笔记本电脑 | 5999 | 电子
Python编程书 | 89 | 图书
无线鼠标 | 159 | 电子
咖啡杯 | 45 | 生活
解决方案¶
方法1:使用字符串格式化
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]
场景描述¶
从文本中提取电话号码和邮箱地址,用于自动化处理联系信息。
前置引导¶
文本中包含多种格式的联系信息:
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:使用正则表达式提取
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]
场景描述¶
结合所有学到的知识,创建一个灵活的报告生成器,支持不同对齐方式。
前置引导¶
销售数据包含产品名称和价格:
sales_data = [
("产品A", "¥1,200"),
("产品B", "¥3,450"),
("产品C", "¥890"),
("总计", "¥5,540")
]
需要生成格式化的报告,支持左对齐、居中、右对齐三种方式。
预期结果¶
销售报告
=====================
产品A : ¥1,200
产品B : ¥3,450
产品C : ¥890
总计 : ¥5,540
解决方案¶
方法1:通用报告生成器
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'))
要求: 修改代码,使其支持自动计算列宽,确保美观显示
结合字符串格式化、对齐、宽度计算等技巧
支持多种对齐方式,灵活适应不同需求
自动计算列宽,确保美观显示