공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
139 lines
4.7 KiB
Python
139 lines
4.7 KiB
Python
import sys,io,re,json,copy
|
|
import openpyxl
|
|
from openpyxl.utils import get_column_letter
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
|
|
SRC='충청남도_아산시.xlsx'; OUT='_rebuilt.xlsx'
|
|
wb=openpyxl.load_workbook(SRC); ws=wb.active
|
|
plan=json.load(open('_plan_out.json',encoding='utf-8'))
|
|
existing={int(k):v for k,v in plan['existing'].items()} # row -> [row,L,M]
|
|
groups={g['row']:g for g in plan['groups']}
|
|
INFLATED={'어문,이미지,영상','어문,이미지,영상,오디오','어문,영상'}
|
|
|
|
# effective (merge-filled) value getter
|
|
mergemap={}
|
|
for mr in ws.merged_cells.ranges:
|
|
for rr in range(mr.min_row,mr.max_row+1):
|
|
for cc in range(mr.min_col,mr.max_col+1):
|
|
mergemap[(rr,cc)]=(mr.min_row,mr.min_col)
|
|
def eff(r,c):
|
|
t=mergemap.get((r,c),(r,c)); return ws.cell(*t).value
|
|
def raw(r,c): return ws.cell(r,c).value
|
|
|
|
# capture reference styles per column from row 5 (data row)
|
|
REFROW=5
|
|
refstyle={}
|
|
for c in range(2,28):
|
|
cell=ws.cell(REFROW,c)
|
|
refstyle[c]=dict(font=copy.copy(cell.font),border=copy.copy(cell.border),
|
|
fill=copy.copy(cell.fill),alignment=copy.copy(cell.alignment),
|
|
number_format=cell.number_format)
|
|
# K hyperlink ref style
|
|
kcell=ws.cell(5,11); kstyle=dict(font=copy.copy(kcell.font))
|
|
|
|
# ---- build records ----
|
|
# each record: dict col(2..27)->value ; D-J=4..10, K=11, L=12, M=13, N=14, O=15, P=16, Q=17, R=18, S=19, T..AA=20..27
|
|
records=[]
|
|
def base_cols(r):
|
|
"""effective D..J for row r"""
|
|
return {c:eff(r,c) for c in range(4,11)}
|
|
|
|
# rows 3-15 keep as-is (effective D-J + raw K-AA)
|
|
for r in range(3,16):
|
|
if not raw(r,11): continue
|
|
rec={}
|
|
for c in range(4,11): rec[c]=eff(r,c)
|
|
for c in range(11,28): rec[c]=raw(r,c)
|
|
records.append(rec)
|
|
|
|
# rows 16-270
|
|
for r in range(16,271):
|
|
if not raw(r,11): continue
|
|
if r in groups:
|
|
g=groups[r]; col=g['col']
|
|
parent={c:eff(r,c) for c in range(4,col+1)} # D..col (group label at col)
|
|
for k in g['kids']:
|
|
rec={}
|
|
for c in range(4,col+1): rec[c]=parent[c]
|
|
rec[col+1]=k['label']
|
|
rec[11]=k['url']; rec[12]=k['L']; rec[13]=k['M']
|
|
rec[14]=k['N']; rec[15]=k['O']; rec[19]=k['S'] or None
|
|
records.append(rec)
|
|
else:
|
|
L=existing[r][1]; M=existing[r][2]
|
|
rec={}
|
|
for c in range(4,11): rec[c]=eff(r,c)
|
|
rec[11]=raw(r,11); rec[12]=L; rec[13]=(M if M!='' else None)
|
|
# N
|
|
curN=raw(r,14)
|
|
if L=='사이트': rec[14]=None
|
|
elif L=='페이지': rec[14]='어문' if curN in INFLATED else curN
|
|
else: rec[14]=curN
|
|
# O,P,Q,R,S,T-AA
|
|
rec[15]=(None if L=='사이트' else raw(r,15))
|
|
for c in [16,17,18,19,20,21,22,23,24,25,26,27]: rec[c]=raw(r,c)
|
|
records.append(rec)
|
|
|
|
print('total records:',len(records))
|
|
|
|
# ---- clear data region & unmerge data merges ----
|
|
hdr_keep={'B1:R1','S1:W1','Y1:AA1'}
|
|
for mr in list(ws.merged_cells.ranges):
|
|
if str(mr) not in hdr_keep:
|
|
ws.unmerge_cells(str(mr))
|
|
maxr=ws.max_row
|
|
for r in range(3,maxr+1):
|
|
for c in range(2,28):
|
|
ws.cell(r,c).value=None
|
|
ws.cell(r,c).hyperlink=None
|
|
|
|
# ---- write records ----
|
|
def apply_style(cell,c):
|
|
s=refstyle[c]
|
|
cell.font=copy.copy(s['font']); cell.border=copy.copy(s['border'])
|
|
cell.fill=copy.copy(s['fill']); cell.alignment=copy.copy(s['alignment'])
|
|
cell.number_format=s['number_format']
|
|
for i,rec in enumerate(records):
|
|
R=3+i
|
|
ws.cell(R,2).value=i+1 # B 순번
|
|
apply_style(ws.cell(R,2),2)
|
|
for c in range(4,28):
|
|
v=rec.get(c)
|
|
cell=ws.cell(R,c)
|
|
cell.value=v
|
|
apply_style(cell,c)
|
|
# K hyperlink
|
|
kv=rec.get(11)
|
|
if kv and isinstance(kv,str) and kv.startswith('http'):
|
|
ws.cell(R,11).hyperlink=kv
|
|
ws.cell(R,11).font=copy.copy(kstyle['font'])
|
|
# C 사이트명 always 아산시
|
|
ws.cell(R,3).value='아산시'; apply_style(ws.cell(R,3),3)
|
|
last=3+len(records)-1
|
|
|
|
# ---- hierarchical re-merge D..I (4..9) ----
|
|
# capture full (uncleared) category values FIRST so merge keys stay stable
|
|
catvals={}
|
|
for i in range(len(records)):
|
|
R=3+i
|
|
for c in range(4,11): catvals[(R,c)]=ws.cell(R,c).value
|
|
for c in range(4,10):
|
|
r=3
|
|
while r<=last:
|
|
key=tuple(catvals[(r,cc)] for cc in range(4,c+1))
|
|
v=catvals[(r,c)]
|
|
if v in (None,''):
|
|
r+=1; continue
|
|
r2=r
|
|
while r2+1<=last:
|
|
key2=tuple(catvals[(r2+1,cc)] for cc in range(4,c+1))
|
|
if key2==key: r2+=1
|
|
else: break
|
|
if r2>r:
|
|
for rr in range(r+1,r2+1): ws.cell(rr,c).value=None
|
|
ws.merge_cells(start_row=r,start_column=c,end_row=r2,end_column=c)
|
|
r=r2+1
|
|
|
|
wb.save(OUT)
|
|
print('saved',OUT,'rows 3..',last)
|