112 lines
3.4 KiB
Python
112 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
比较两个学生 Excel 文件的表头(列名)。
|
|
|
|
用法:
|
|
python compare_student_headers.py \
|
|
--file-a 学校历史数据迁移/student1222.xls \
|
|
--file-b 学校历史数据迁移/student1127.xls
|
|
|
|
脚本会打印:
|
|
- 是否完全相同(顺序及名称)
|
|
- 仅在 A 中存在的列
|
|
- 仅在 B 中存在的列
|
|
- 顺序不同但内容相同的列(名称相同但位置不同)
|
|
"""
|
|
from __future__ import annotations
|
|
import os
|
|
import sys
|
|
import argparse
|
|
from typing import List
|
|
import pandas as pd
|
|
|
|
|
|
def read_headers(path: str) -> List[str]:
|
|
if not os.path.exists(path):
|
|
raise FileNotFoundError(path)
|
|
ext = os.path.splitext(path)[1].lower()
|
|
if ext == ".xls":
|
|
df = pd.read_excel(path, nrows=0, engine="xlrd")
|
|
else:
|
|
# .xlsx or others
|
|
df = pd.read_excel(path, nrows=0, engine="openpyxl")
|
|
return [str(c).strip() for c in list(df.columns)]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--file-a", type=str, required=True)
|
|
parser.add_argument("--file-b", type=str, required=True)
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
headers_a = read_headers(args.file_a)
|
|
except Exception as e:
|
|
print(f"读取 {args.file_a} 表头失败: {e}")
|
|
sys.exit(2)
|
|
try:
|
|
headers_b = read_headers(args.file_b)
|
|
except Exception as e:
|
|
print(f"读取 {args.file_b} 表头失败: {e}")
|
|
sys.exit(2)
|
|
|
|
print(f"{args.file_a} 列数: {len(headers_a)}")
|
|
print(f"{args.file_b} 列数: {len(headers_b)}")
|
|
|
|
if headers_a == headers_b:
|
|
print("表头完全相同(顺序及名称一致)。")
|
|
return
|
|
|
|
set_a = set(headers_a)
|
|
set_b = set(headers_b)
|
|
only_a = sorted(list(set_a - set_b))
|
|
only_b = sorted(list(set_b - set_a))
|
|
|
|
if not only_a and not only_b:
|
|
print("列集合相同,但顺序不同。")
|
|
# show first few mismatches by position
|
|
diffs = []
|
|
for i, (ca, cb) in enumerate(zip(headers_a, headers_b)):
|
|
if ca != cb:
|
|
diffs.append((i + 1, ca, cb))
|
|
if diffs:
|
|
print("位置不一致的前若干列(位置, A列名, B列名):")
|
|
for d in diffs[:20]:
|
|
print(f" {d[0]:>3}: {d[1]} | {d[2]}")
|
|
else:
|
|
# maybe lengths differ; list remainder
|
|
if len(headers_a) != len(headers_b):
|
|
print("两表长度不同,下面列出多余部分:")
|
|
if len(headers_a) > len(headers_b):
|
|
print("A 多余:", headers_a[len(headers_b):len(headers_b)+20])
|
|
else:
|
|
print("B 多余:", headers_b[len(headers_a):len(headers_a)+20])
|
|
return
|
|
|
|
# print differences
|
|
if only_a:
|
|
print(f"仅在 A 中存在的列 ({len(only_a)}):")
|
|
for c in only_a[:100]:
|
|
print(" -", c)
|
|
if only_b:
|
|
print(f"仅在 B 中存在的列 ({len(only_b)}):")
|
|
for c in only_b[:100]:
|
|
print(" -", c)
|
|
|
|
# also list positional mismatches up to 20
|
|
diffs = []
|
|
for i in range(min(len(headers_a), len(headers_b))):
|
|
if headers_a[i] != headers_b[i]:
|
|
diffs.append((i + 1, headers_a[i], headers_b[i]))
|
|
if diffs:
|
|
print("位置不一致的前若干列(位置, A列名, B列名):")
|
|
for d in diffs[:20]:
|
|
print(f" {d[0]:>3}: {d[1]} | {d[2]}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
|