
本文教你用 python 自动识别同日期的 report1 和 report2 文件(如 “report1file 02.04.2024.xlsx” 与 “report2file 02.04.2024.xlsx”),逐对加载、清洗并比对差异,避免手动指定日期,提升报表验证效率。
本文教你用 python 自动识别同日期的 report1 和 report2 文件(如 “report1file 02.04.2024.xlsx” 与 “report2file 02.04.2024.xlsx”),逐对加载、清洗并比对差异,避免手动指定日期,提升报表验证效率。
在实际数据处理流程中,频繁依赖 date.today() 硬编码当前日期会严重限制回溯分析能力——你无法自动比对历史日期(如 01.04.2024)生成的成对报表。本教程提供一套健壮、可复用的解决方案:基于文件名自动提取日期、智能分组配对、统一清洗逻辑、逐对差异比对。
✅ 核心思路
- 不依赖系统日期:从文件名中解析真实日期(支持 DD.MM.YYYY 或 YYYY-MM-DD 格式);
- 精准配对:按日期聚合所有文件,确保每个日期下严格匹配 Report1File* 和 Report2File* 各一个;
- 函数化封装:将清洗(CSV → Excel)与比对逻辑解耦为可复用函数,避免重复代码;
- 健壮容错:自动跳过缺失配对、格式异常或读取失败的文件,并给出清晰提示。
? 完整实现代码
import os
import re
import pandas as pd
from datetime import datetime
from pathlib import Path
# ✅ 配置项(按需修改)
DATA_DIR = Path("C:/Users/User/Python/Project/") # 存放所有 Report*.xlsx 的目录
REPORT1_PATTERN = r"Report1File[ _](\d{2}\.\d{2}\.\d{4}|\d{4}-\d{2}-\d{2})"
REPORT2_PATTERN = r"Report2File[ _](\d{2}\.\d{2}\.\d{4}|\d{4}-\d{2}-\d{2})"
def parse_date_from_filename(filename: str) -> datetime | None:
"""从文件名提取日期对象,支持 '02.04.2024' 和 '2024-04-02' 两种格式"""
for pattern in [REPORT1_PATTERN, REPORT2_PATTERN]:
match = re.search(pattern, filename)
if match:
date_str = match.group(1)
try:
if "." in date_str: # DD.MM.YYYY
return datetime.strptime(date_str, "%d.%m.%Y")
else: # YYYY-MM-DD
return datetime.strptime(date_str, "%Y-%m-%d")
except ValueError:
continue
return None
def clean_and_save_csv(csv_path: Path, output_name: str) -> Path | None:
"""标准化清洗 CSV 并保存为 Excel(复用原逻辑,但去硬编码)"""
try:
df = pd.read_csv(csv_path, header=None)
# 拆分首列(逗号分隔)
max_commas = df[0].str.split(',').apply(len).max()
col_names = [f"name_{i}" for i in range(max_commas)]
df[col_names] = df[0].str.split(',', expand=True)
df = df.drop(columns=[0]) # 删除原始列
# 移除含 'name_0' 的列(原意为时间戳列,此处按列名模糊过滤)
time_cols = [col for col in df.columns if "name_0" in str(col)]
df = df.drop(columns=time_cols, errors='ignore')
# 保存
output_path = DATA_DIR / f"{output_name}.xlsx"
df.to_excel(output_path, index=False)
print(f"✅ Cleaned & saved: {output_path.name}")
return output_path
except Exception as e:
print(f"❌ Failed to process {csv_path.name}: {e}")
return None
def compare_pair(file1: Path, file2: Path) -> bool:
"""比对一对 Excel 文件,返回是否有差异"""
try:
# 跳过前几行(根据原始逻辑:Report1跳2行,Report2跳3行)
skip1 = 2 if "Report1" in file1.name else 0
skip2 = 3 if "Report2" in file2.name else 0
df1 = pd.read_excel(file1, skiprows=skip1)
df2 = pd.read_excel(file2, skiprows=skip2)
# 使用 pandas 1.1.0+ 的 compare() 方法(要求索引/列完全一致)
diff = df1.compare(df2, keep_shape=True, keep_equal=False)
if diff.empty:
print(f"✔️ {file1.name} ↔ {file2.name}: No differences found.")
return False
else:
print(f"⚠️ {file1.name} ↔ {file2.name}: Differences detected!")
print(diff.head(10)) # 仅显示前10行差异,防刷屏
return True
except Exception as e:
print(f"❌ Comparison failed for {file1.name} & {file2.name}: {e}")
return False
# --- 主流程:自动发现 → 分组配对 → 批量比对 ---
if __name__ == "__main__":
# Step 1: 收集所有 Report*.xlsx 文件并按日期分组
xlsx_files = list(DATA_DIR.glob("Report*File*.xlsx"))
if not xlsx_files:
print("⚠️ No Report*.xlsx files found in directory.")
exit()
# 按日期分组:{date_obj: {"Report1": Path, "Report2": Path}}
date_groups = {}
for f in xlsx_files:
dt = parse_date_from_filename(f.name)
if dt is None:
print(f"? Skipped unrecognized filename: {f.name}")
continue
date_key = dt.date()
if date_key not in date_groups:
date_groups[date_key] = {"Report1": None, "Report2": None}
if "Report1" in f.name and not date_groups[date_key]["Report1"]:
date_groups[date_key]["Report1"] = f
elif "Report2" in f.name and not date_groups[date_key]["Report2"]:
date_groups[date_key]["Report2"] = f
# Step 2: 逐对执行比对
total_pairs = len(date_groups)
diff_count = 0
print(f"\n? Starting comparison for {total_pairs} date(s)...\n")
for date_val, pair in sorted(date_groups.items()):
print(f"? Processing date: {date_val.strftime('%d.%m.%Y')}")
if not pair["Report1"] or not pair["Report2"]:
missing = "Report1" if not pair["Report1"] else "Report2"
print(f"❌ Incomplete pair — missing {missing} for {date_val.strftime('%d.%m.%Y')}")
continue
if compare_pair(pair["Report1"], pair["Report2"]):
diff_count += 1
# Step 3: 总结
print(f"\n? Summary: {diff_count}/{total_pairs} date(s) have differences.")
if diff_count == 0:
print("? All paired reports match perfectly.")⚠️ 关键注意事项
- 文件命名一致性:脚本依赖正则匹配 Report1File/Report2File + 日期。请确保历史文件命名规范(如 Report1File 01.04.2024.xlsx,空格或下划线均可)。
- 日期格式兼容性:已同时支持 DD.MM.YYYY(欧洲格式)和 YYYY-MM-DD(ISO 格式)。若使用其他格式(如 MM/DD/YYYY),需调整 parse_date_from_filename() 中的 strptime 模式。
- 跳过行数灵活性:skiprows 参数根据文件名自动判断(Report1 跳 2 行,Report2 跳 3 行),你可根据实际 Excel 表头结构调整。
- 性能优化建议:若文件极多,可添加 concurrent.futures.ThreadPoolExecutor 实现并行比对(注意 pandas 的线程安全性)。
- 扩展性提示:未来如增加 Report3File*,只需新增正则模式、扩展 date_groups 字典结构,并复用 compare_pair() 逻辑即可。
通过此方案,你彻底摆脱了“每天手动改日期”的低效操作,一次运行即可完成全量历史报表的自动化校验,真正实现数据质量闭环。

















