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"
]

前置引导

原始数据存在以下问题:

  • 首尾空格不一致

  • 大小写格式混乱

  • 姓名分隔符不统一

需要完成以下清洗任务:

  1. 去除首尾空格

  2. 将姓名格式化为"首字母大写"

  3. 用下划线连接名和姓

预期结果

原始数据: ['  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'))

要求: 修改代码,使其支持自动计算列宽,确保美观显示

  • 结合字符串格式化、对齐、宽度计算等技巧

  • 支持多种对齐方式,灵活适应不同需求

  • 自动计算列宽,确保美观显示