CSV成绩单按班级自动拆分成多文件(附完整脚本+实测记录)
老师场景的刚需:教务导出一个大CSV,全班混在一起,要分发给各班班主任,就得按班级拆成多个文件。手动复制粘贴又慢又容易漏行。下面这份脚本 30 行搞定,本文所有数字都是实际运行结果。
脚本要处理的真实脏数据
- 编码混乱:教务系统导出常是 GBK,苹果/谷歌表格导出是 UTF-8(可能带BOM)。写死一种编码直接崩。
- 班级名带空格:
"二班 "(尾部多了个空格)会被当成第四个班,单独拆出一个只有一个学生的文件——数据静默分错,比报错可怕。 - 表头不一致:补录文件列名对不上时,应该报出文件名跳过,而不是静默混进数据。
完整脚本
import csv, os
from collections import defaultdict
def read_csv_auto(path):
raw = open(path, 'rb').read()
for enc in ('utf-8-sig', 'gbk'):
try:
return list(csv.reader(raw.decode(enc).splitlines())), enc
except UnicodeDecodeError:
pass
raise ValueError(path + ": 无法识别编码")
HEADER = ["姓名", "班级", "语文", "数学", "英语"]
groups = defaultdict(list)
header = None
for fn in sorted(os.listdir('in')):
data, enc = read_csv_auto('in/' + fn)
if data[0] != HEADER:
print(f"跳过 {fn}: 表头不符")
continue
if header is None:
header = data[0]
for r in data[1:]:
cls = r[1].strip() # 关键:班级名去空格
if not cls:
print(f"跳过 {fn} 空班级行: {r[0]}")
continue
groups[cls].append(r)
os.makedirs('out', exist_ok=True)
for cls, rs in sorted(groups.items()):
with open(f'out/{cls}.csv', 'w', newline='', encoding='utf-8-sig') as f:
w = csv.writer(f)
w.writerow(header)
w.writerows(rs)
print(f"out/{cls}.csv: {len(rs)} 人")
实跑结果(本文数据当场生成、当场拆分核对)
输入 3 个文件共 43 条学生记录:
in/成绩.csv:40 条,GBK 编码in/成绩补录.csv:2 条,UTF-8 带 BOMin/二班空格.csv:1 条,班级写的是"二班 "(带尾部空格)
输出:
out/一班.csv: 10 人
out/三班.csv: 15 人
out/二班.csv: 18 人
合计 43
10 + 15 + 18 = 43,与输入条数完全一致;"二班 "那行已正确归入out/二班.csv(逐文件 grep 验证),没有被拆成假班级。
三个实测踩过的坑
- 编码写死必崩:
open(path, encoding='gbk')遇到带BOM的UTF-8文件抛 UnicodeDecodeError。先读二进制,按utf-8-sig → gbk顺序尝试解码。 - 班级名不 strip 会静默分错:
"二班 "≠"二班",字典里多出一个键,输出多一个残缺文件,没人会注意到少了一个人。一行.strip()修复。 - 拆完必须做合计核对:输出各班人数之和必须等于输入数据行数。43=43 才能确认没有行被吞掉。这一步不能省——CSV解析不会丢行,但你的过滤逻辑会。
改成按其他列拆
把 r[1] 换成任意列的下标(0 起)就能按科目、按年级、按部门拆。要拆 Excel(.xlsx)而不是 CSV,加一行 pip install openpyxl,把读取部分换成 openpyxl.load_workbook(path).active 遍历行即可,拆分逻辑完全不变。
需要代写这类批量脚本(按你的真实表结构调整、加异常处理、交付可运行文件),可以在喵窝资源铺下单「脚本代写」档(¥19.9),或先在客服对话框聊聊需求。