공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94 lines
3.9 KiB
Python
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()
|