import openpyxl, json, sys, os, shutil, time from copy import copy from openpyxl.styles import PatternFill from openpyxl.utils import get_column_letter sys.stdout.reconfigure(encoding='utf-8') P=r'작업파일/공공기관2/12.한국철도공사/한국철도공사.xlsx' BASE='https://info.korail.com' BLUE=PatternFill(fill_type='solid', fgColor='FFBDD7EE', bgColor='FFBDD7EE') ts=json.load(open(r'작업파일/공공기관2/12.한국철도공사/_tabscan.json',encoding='utf-8')) EXPAND=[6,8,15,30,33,34,37,38,39,40,45,46,47,74,78,79,80,82,86,92,93,94,102,104,105,106] IMG=set('719 720 730 769 781 783 785 799 871 872 894 899 900 901 902 906 907 908 970 2950 2951 2952 2977 1461 1462 1463 1464 1641 1303 1541 1503 1504 2730 1505 2731 1507 1508 2732 1510 1511'.split()) def nfor(key): return '어문,이미지' if str(key) in IMG else '어문' mt0=os.path.getmtime(P) shutil.copy2(P, P.replace('.xlsx', f'_backup_{int(mt0)}.xlsx')) wb=openpyxl.load_workbook(P) ws=wb.active # merge-fill map cols 4-10 fill={} for m in list(ws.merged_cells.ranges): v=ws.cell(m.min_row,m.min_col).value for rr in range(m.min_row,m.max_row+1): for cc in range(m.min_col,m.max_col+1): fill[(rr,cc)]=v def eff(r,c): return fill.get((r,c), ws.cell(r,c).value) # capture template styles per column from a clean data row (row 4) TPL={} for c in range(2,28): cell=ws.cell(4,c) TPL[c]=(copy(cell.font),copy(cell.border),copy(cell.fill),copy(cell.alignment),copy(cell.number_format)) # K hyperlink template style (font/color) KSTYLE=(copy(ws.cell(3,11).font),copy(ws.cell(3,11).border),copy(ws.cell(3,11).fill),copy(ws.cell(3,11).alignment)) Cval=ws.cell(3,3).value # 사이트명 # Build records: list of dicts col->value, plus 'blue' set of cols, plus 'hl' url records=[] for r in range(3, ws.max_row+1): base={} for c in range(3,28): # C..AA (B renumbered later) if 4<=c<=10: base[c]=eff(r,c) else: base[c]=ws.cell(r,c).value hl=ws.cell(r,11).hyperlink.target if ws.cell(r,11).hyperlink else (base[11] if base[11] else None) if r in EXPAND: leafcol=6 # F tabs=ts[str(r)]['tabs'] # self tab = active (first); reuse this row but add G label + url stays for i,t in enumerate(tabs): rec=dict(base) key=t['href'].split('key=')[-1] url=BASE+t['href'] rec[7]=t['label'] # G rec[11]=url # K value rec['_hl']=url rec[12]='페이지' # L rec[13]=1 # M rec[14]=nfor(key) # N rec[15]='미부착' # O rec['_blue']={7,11,12,13,14,15} if i>0: # new row: clear D,E,F values (merge covers) - keep for run-length; keep eff values rec[16]=None; rec[17]=None # P,Q clear for new for cc in range(18,28): rec[cc]=None # R-AA clear records.append(rec) else: rec=dict(base); rec['_hl']=hl; rec['_blue']=set() records.append(rec) # Now rewrite sheet: clear merges + data region for m in list(ws.merged_cells.ranges): ws.unmerge_cells(str(m)) maxr=ws.max_row for r in range(3, maxr+1): for c in range(1,28): cell=ws.cell(r,c); cell.value=None; cell.hyperlink=None # write records import re for idx,rec in enumerate(records): r=3+idx ws.cell(r,2).value=idx+1 # B renumber # apply template style to all cols for c in range(2,28): f,b,fl,al,nf=TPL[c] cell=ws.cell(r,c) cell.font=copy(f); cell.border=copy(b); cell.fill=copy(fl); cell.alignment=copy(al); cell.number_format=nf for c in range(3,28): ws.cell(r,c).value=rec.get(c) # K hyperlink url=rec.get('_hl') if url and isinstance(url,str) and url.startswith('http'): kc=ws.cell(r,11) kc.hyperlink=url kf,kb,kfl,kal=KSTYLE kc.font=copy(kf) # blue highlights for c in rec.get('_blue',()): ws.cell(r,c).fill=copy(BLUE) nrows=len(records) last=3+nrows-1 # snapshot of effective values BEFORE merging (merged cells read back as None) SNAP={} for idx,rec in enumerate(records): rr=3+idx for c in range(4,11): SNAP[(rr,c)]=rec.get(c) # run-length merges for cols D(4)..J(10) def val(r,c): return SNAP.get((r,c)) for c in range(4,11): r=3 while r<=last: v=val(r,c) if v is None: r+=1; continue # ancestor tuple def anctup(rr): return tuple(val(rr,cc) for cc in range(4,c)) a0=anctup(r) r2=r while r2+1<=last and val(r2+1,c)==v and anctup(r2+1)==a0: r2+=1 if r2>r: ws.merge_cells(start_row=r,start_column=c,end_row=r2,end_column=c) r=r2+1 # mtime guard + save if os.path.getmtime(P)!=mt0: print('ABORT mtime moved'); sys.exit(2) try: wb.save(P) except PermissionError as e: print('ABORT-PERM (close Excel)', e); sys.exit(3) print('OK rows', nrows, '(was', maxr-2, ') new', nrows-(maxr-2))