import sys, io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') import openpyxl, importlib.util from openpyxl.utils import get_column_letter from collections import Counter P = r'D:\01.프로젝트\DB수집\작업파일\광역_사이트맵\충청남도\8.서산시\충청남도_서산시.xlsx' wb=openpyxl.load_workbook(P); ws=wb.active M=list(ws.merged_cells.ranges) def mof(r,c): for m in M: if m.min_row<=r<=m.max_row and m.min_col<=c<=m.max_col: return m return None def eff(r,c): m=mof(r,c); return ws.cell(m.min_row,m.min_col).value if m else ws.cell(r,c).value data=[r for r in range(3,ws.max_row+1) if ws.cell(r,2).value not in (None,'')] print(f'시트:{ws.title} 데이터행:{len(data)} max_row:{ws.max_row} 총병합:{len(M)}') print('헤더병합:', [h for h in ('B1:R1','S1:W1','Y1:AA1') if h in {str(m) for m in M}]) # 1) 구조검수 (검수체크 재사용) spec=importlib.util.spec_from_file_location('chk', r'D:\01.프로젝트\DB수집\작업파일\광역_사이트맵\_검수체크.py') chk=importlib.util.module_from_spec(spec); spec.loader.exec_module(chk) n,issues=chk.inspect(P) print(f'\n=== 구조검수: {"PASS" if not issues else "FAIL "+str(len(issues))+"건"} ===') for x in issues: print(' ✗',x) # 2) 정렬 분포 (가로/세로/wrap) per 주요 컬럼 print('\n=== 정렬 분포 (열: (horiz,vert,wrap) -> 행수) ===') for c in (2,4,5,6,7,11,13,14,15): cnt=Counter() for r in data: a=ws.cell(r,c).alignment cnt[(a.horizontal, a.vertical, a.wrap_text)]+=1 print(f' {get_column_letter(c)}: {dict(cnt)}') # 3) 행높이 hc=Counter(ws.row_dimensions[r].height for r in range(1,ws.max_row+1)) print('\n행높이 분포:', dict(hc)) # 4) 미병합 부모그룹 탐지 (E5,F6,G7) def parent_groups(c): groups=[]; i=0 while i1 and any(ws.cell(rr,c+1).value not in (None,'') for rr in rows): m=mof(r,c); groups.append((rows[0],rows[-1],v,bool(m and m.max_row>m.min_row))); i=j else: i+=1 return groups print('\n=== 부모그룹 병합상태 (★비병합=이상후보) ===') for c,nm in [(5,'E'),(6,'F'),(7,'G')]: gs=parent_groups(c) if not gs: continue un=[g for g in gs if not g[3]] print(f' {nm}: 총{len(gs)} 병합{len(gs)-len(un)} ★비병합{len(un)}') for a,z,v,mg in un: print(f' ★ {nm}{a}:{z} {v!r} (E={eff(a,5)!r} F={eff(a,6)!r})')