DB_JOB/_김제_정리.py
hehihoho3 df16c98366 백업: DB수집 전체 스냅샷 (공공기관2 정리 전)
공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 18:15:40 +09:00

94 lines
3.9 KiB
Python

# -*- coding: utf-8 -*-
"""김제시 후처리 2규칙:
R1) F가 병합(같은 D,E,F 연속 ≥2행)인데 그 블록 '첫 행'의 G가 비어있으면 그 행 삭제(부모 랜딩 셸).
R2) F 또는 G 텍스트 끝이 '새창열림'이면 → L=사이트, M·N·O·P·Q 삭제, 텍스트에서 '새창열림' 제거.
사용: python -X utf8 _김제_정리.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')
NEWWIN = re.compile(r'\s*새\s*창\s*열림\s*$')
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)
# --- R2: 새창열림 — 행의 leaf(가장 깊은 카테고리) 라벨 끝이 새창열림이면 사이트화 ---
r2 = []
for r in rows:
v = r['vals']
lc = dd.leaf_depth(v) # 가장 깊은 카테고리 컬럼(E/F/G…)
t = v.get(lc)
if isinstance(t, str) and NEWWIN.search(t):
r2.append(r)
# 적용: 사이트화 + M/N/O/P/Q 삭제. 텍스트 strip 은 전체 행·전 카테고리 컬럼에서.
for r in r2:
v = r['vals']
r['_had_pq'] = any(v.get(c) not in (None, '') for c in (16, 17))
v[12] = '사이트' # L
for c in (13, 14, 15, 16, 17): # M N O P Q
v[c] = None
# 새창열림 텍스트 제거(모든 행, D~J)
for r in rows:
v = r['vals']
for c in range(4, 11):
t = v.get(c)
if isinstance(t, str) and NEWWIN.search(t):
v[c] = NEWWIN.sub('', t).strip()
# --- R1: F-block 첫행 G 비면 삭제 ---
# F-block = 같은 (D,E,F) 연속 run, F 비어있지 않음, run길이>=2
delete = set() # id(row)
n = len(rows)
i = 0
while i < n:
v = rows[i]['vals']
F = v.get(6)
if F in (None, ''):
i += 1; continue
j = i
while j + 1 < n and rows[j+1]['vals'].get(6) == F \
and rows[j+1]['vals'].get(4) == v.get(4) \
and rows[j+1]['vals'].get(5) == v.get(5):
j += 1
runlen = j - i + 1
if runlen >= 2 and rows[i]['vals'].get(7) 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('=== 김제 정리 plan ===')
print(f'기존행 {len(rows)}')
print(f'\n[R2] 새창열림 → 사이트: {len(r2)}건 (그중 P/Q 보유 {sum(1 for r in r2 if r.get("_had_pq"))}건)')
for r in r2[:40]:
print(f' r{r["src"]}: {lab(r["vals"])}')
print(f'\n[R1] F병합 첫행 G빈칸 → 삭제: {len(del_rows)}')
for r in del_rows[:60]:
print(f' r{r["src"]}: {lab(r["vals"])} (K={str(r["vals"].get(11))[-40:]})')
print(f'\n결과행: {len(rows)}{len(keep)}')
if mode != 'run':
return
bak = XP.replace('.xlsx', '_backup_정리전.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:
alt = XP.replace('.xlsx', '_LP.xlsx'); wb.save(alt); print(f'\n!! 잠김 → {os.path.basename(alt)}')
if __name__ == '__main__':
main()