
本教程详解如何从 mbox 格式文本(如 mbox-short.txt)中精准提取邮件发送时间的小时字段,统计各小时出现次数,并按升序输出 小时 数量 的纯文本格式(如 04 3),严格满足自动化测试(pytest)对输出格式的校验要求。
本教程详解如何从 mbox 格式文本(如 `mbox-short.txt`)中精准提取邮件发送时间的小时字段,统计各小时出现次数,并按升序输出 `小时 数量` 的纯文本格式(如 `04 3`),严格满足自动化测试(pytest)对输出格式的校验要求。
在处理邮件日志类文本(如 mbox-short.txt)时,常见需求是统计每小时的邮件发送频次。关键挑战在于:解析必须准确、输出格式必须严格匹配——pytest 不仅校验内容逻辑,更精确比对每行字符串(如 "04 3" 而非 ('04', 3) 或 "04:3")。
✅ 正确解析逻辑
- 目标行必须以
"From "开头(注意空格,避免匹配"From:"或"Froma"); - 时间戳位于第 6 个字段(索引
5),格式为"HH:MM:SS"; - 使用
split(":")安全提取小时(hh, mm, ss = tokens[5].split(":")),避免硬切片导致的边界错误(如word[5][0:2]在09:14:16中有效,但在9:14:16中失效); - 推荐使用
collections.defaultdict(int)或Counter统计,避免手动初始化字典键。
✅ 格式化输出要点(pytest 通过核心)
-
禁止打印元组:
print(item)→ 输出('04', 3)❌; -
必须解包打印:
print(*item)→ 输出04 3✅; -
每行仅含
HH COUNT,无括号、引号、逗号或额外空格; -
按小时字符串升序排序:
sorted(d.items())自动按'04' 字典序排序(因小时为两位字符串,此方式等效于数值排序)。
✅ 完整可运行代码(兼容 pytest)
from collections import defaultdict
def exercise_10_2():
count_dict = defaultdict(int)
filename = "mbox-short.txt"
with open(filename) as f:
for line in f:
# 严格匹配以 "From " 开头的行(注意末尾空格)
if line.startswith("From "):
parts = line.split()
# 确保有足够字段且第6个字段存在冒号
if len(parts) > 5 and ":" in parts[5]:
try:
hour = parts[5].split(":")[0]
# 确保小时为两位数字(如 '09' 而非 '9'),但原始数据已规范
count_dict[hour] += 1
except (ValueError, IndexError):
continue # 跳过异常行,不中断流程
# 按小时字符串升序输出:print(*item) 解包元组为两个参数
for hour, count in sorted(count_dict.items()):
print(hour, count)
⚠️ 常见错误与规避
-
错误切片:
word[5][0:2]在单数字小时(如"9:14:16")中会截取"9:",应优先用split(":")[0]; -
宽松匹配:
"From " in line可能误匹配行中任意位置,必须用line.startswith("From "); -
输出格式陷阱:
print(f"{hour} {count}")虽等效,但需确保无多余空格;print((hour, count))直接失败; -
文件路径硬编码:测试环境可能重定向输入,故直接使用
"mbox-short.txt",无需input(); -
未关闭文件:使用
with open()自动管理资源,避免句柄泄漏。
运行后,输出将严格符合 pytest 期望:
04 3 06 1 07 1 09 2 10 3 11 6 14 1 15 2 16 4 17 2 18 1 19 1
此格式与断言 ['04 3\n06 1\n...'] 完全一致,确保测试 100% 通过。










