# -*- coding: utf-8 -*- import openpyxl, io, os, glob from collections import defaultdict ROOT=r"D:\01.프로젝트\DB수집" out=io.open(r"D:\01.프로젝트\DB수집\작업파일\_dupname_sweep_out.txt","w",encoding="utf-8") def w(*a): out.write(" ".join(str(x) for x in a)+"\n") SKIP_DIR=("_backup","backup","_temp","제출폴더","_스크립트","_nshots","_naudit","_shots",".git") SKIP_NAME=("backup","conflicted","_작업현황","작업현황","_취합_예시","자료_취합","예시","~$") def is_target(p): pl=p.replace("/","\\") for s in SKIP_DIR: if "\\"+s in pl or "\\"+s+"\\" in pl: return False base=os.path.basename(p) for s in SKIP_NAME: if s in base: return False return base.endswith(".xlsx") files=[] for dp,dn,fn in os.walk(ROOT): # prune skip dirs dn[:]=[d for d in dn if d not in SKIP_DIR and "backup" not in d.lower()] for f in fn: p=os.path.join(dp,f) if is_target(p): files.append(p) w("scanned candidate files:",len(files));w("") def eff_leaf_dups(ws): eff={} for r in range(3,ws.max_row+1): for c in range(4,11): eff[(r,c)]=ws.cell(r,c).value for mr in ws.merged_cells.ranges: if mr.min_col>=4 and mr.max_col<=10: v=ws.cell(mr.min_row,mr.min_col).value for r in range(mr.min_row,mr.max_row+1): for c in range(mr.min_col,mr.max_col+1): eff[(r,c)]=v byleaf=defaultdict(list) for r in range(3,ws.max_row+1): # skip empty rows path=[str(eff[(r,c)]).strip() for c in range(4,11) if eff[(r,c)] not in (None,"")] if not path: continue byleaf[path[-1]].append(r) return {k:v for k,v in byleaf.items() if len(v)>1} summary=[] for p in sorted(files): try: wb=openpyxl.load_workbook(p,read_only=False,data_only=True) except Exception as e: w("LOADERR",p,e); continue ws=wb.active if ws.max_row<3: wb.close(); continue dups=eff_leaf_dups(ws) rel=os.path.relpath(p,ROOT) ngroups=len(dups); nduprows=sum(len(v) for v in dups.values()) summary.append((ngroups,nduprows,rel,dups,ws.max_row)) wb.close() summary.sort(reverse=True) w("=== FILES WITH DUPLICATE MENU NAMES (sorted by #groups) ===") for ng,nr,rel,dups,mx in summary: if ng==0: continue w(f"\n[{ng} groups / {nr} rows] {rel} (max_row={mx})") for nm,rs in sorted(dups.items(), key=lambda x:-len(x[1])): w(f" '{nm}' x{len(rs)} rows={rs}") clean=[s for s in summary if s[0]==0] w("\n=== FILES WITH NO DUPLICATE MENU NAMES ===",len(clean)) for ng,nr,rel,dups,mx in clean: w(" OK",rel) out.close() print("done; files:",len(files),"with dups:",sum(1 for s in summary if s[0]>0))