| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- #!/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()
|