# -*- coding: utf-8 -*- """김제시: E가 병합(같은 D,E 연속 ≥2행)인데 그 블록 '첫 행'의 F가 비어있으면 그 행 삭제(중분류 랜딩 셸). F 카테고리 라벨은 자식행이 병합 승계. 사용: python -X utf8 _김제_E셸삭제.py plan | run """ import os, sys, re, io, shutil, importlib.util, warnings warnings.filterwarnings('ignore') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', line_buffering=True) import openpyxl HERE = os.path.dirname(os.path.abspath(__file__)) def _imp(n, p): s = importlib.util.spec_from_file_location(n, p); m = importlib.util.module_from_spec(s); s.loader.exec_module(m); return m dd = _imp('dd', os.path.join(HERE, '_스크립트', '_dedup_all.py')) XP = os.path.join(HERE, '작업파일', '광역_사이트맵', '전북특별자치도', '3.김제시', '전북특별자치도_김제시.xlsx') def lab(v): return ' > '.join(str(v.get(c)) for c in range(4, 11) if v.get(c) not in (None, '')) def main(): mode = sys.argv[1] if len(sys.argv) > 1 else 'plan' wb = openpyxl.load_workbook(XP); ws = wb.active rows = dd.load_flat(ws) # E-block = 같은 (D,E) 연속 run, E 비어있지 않음, run≥2 delete = set() n = len(rows); i = 0 while i < n: v = rows[i]['vals'] E = v.get(5) if E in (None, ''): i += 1; continue j = i while j + 1 < n and rows[j+1]['vals'].get(5) == E and rows[j+1]['vals'].get(4) == v.get(4): j += 1 runlen = j - i + 1 if runlen >= 2 and rows[i]['vals'].get(6) in (None, ''): delete.add(id(rows[i])) i = j + 1 del_rows = [r for r in rows if id(r) in delete] keep = [r for r in rows if id(r) not in delete] print('=== 김제 E셸삭제 plan ===') print(f'기존행 {len(rows)} → {len(keep)} (삭제 {len(del_rows)})') for r in del_rows: v = r['vals'] print(f' r{r["src"]}: {lab(v)} | L={v.get(12)} M={v.get(13)} | K={str(v.get(11))[-38:]}') if mode != 'run': return bak = XP.replace('.xlsx', '_backup_E셸전.xlsx') shutil.copy(XP, bak) dd.write_back(ws, keep) try: wb.save(XP); print(f'\n저장완료 {len(rows)}→{len(keep)}행. 백업 {os.path.basename(bak)}') except PermissionError: wb.save(XP.replace('.xlsx', '_LP.xlsx')); print('\n!! 잠김 → _LP') if __name__ == '__main__': main()