# -*- coding: utf-8 -*- """건설업 임금실태조사 보고서 HWP(5.x) → 전체본 md + 장별 md 4개. (PDF 가 없는 회차용) 사용: python cak_hwp_md.py <회차 폴더> ... (폴더 안에 .hwp 한 개) - HWP 본문 레코드에서 글·표(칸 좌표 · 병합)를 직접 읽음. 쪽 구분은 HWP 에 없으므로 쪽 표기 없음. - 검증은 cak_verify.py 의 회차 사이 대조(같은 공표일 값이 다른 회차 PDF 에도 실려 있음)로 함. """ import re import struct import sys import zlib from pathlib import Path import olefile NUM = r"\(※\d{1,3}(?:,\d{3})+\)|\d{1,3}(?:,\d{3})+|(?= 32: out.append(chr(c)) i += 1 elif c == 9: out.append("\t") i += 8 elif c in (1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23): i += 8 elif c in (10, 13): i += 1 else: i += 1 return "".join(out) def read_blocks(path): """→ [("p", 글) | ("t", 칸목록[(row, col, colspan, rowspan, 글)] , 행수, 열수)]""" o = olefile.OleFileIO(str(path)) comp = o.openstream("FileHeader").read()[36] & 1 recs = [] i = 0 while o.exists(f"BodyText/Section{i}"): d = o.openstream(f"BodyText/Section{i}").read() if comp: d = zlib.decompress(d, -15) p = 0 while p < len(d): h = struct.unpack_from("> 10) & 0x3FF, h >> 20 p += 4 if sz == 0xFFF: sz = struct.unpack_from(" tl or recs[k][0] in (72, 77) and recs[k][1] >= tl ): t2, l2, b2 = recs[k] if t2 == 77: rows, cols = struct.unpack_from("".join(x.strip() for x in t if x.strip() != "")) for r, c, cs, rs, t in cells ], rows, cols, ) ) continue if tag == 67: blocks.append(("p", para_text(b).rstrip("\r"))) k += 1 return blocks def esc(s): return s.replace("|", "\\|") def md_grid(cells, rows, cols): g = [[""] * cols for _ in range(rows)] for r, c, cs, rs, t in cells: if r < rows and c < cols: g[r][c] = t o = [] for i, row in enumerate(g): o.append("| " + " | ".join(esc(x) for x in row) + " |") if i == 0: o.append("|" + "---|" * cols) return o def jobs_table(cells): """개별직종 표 → 행 [(코드, 이름, 신뢰도, [4값])] · 머리 글""" byrow = {} for r, c, cs, rs, t in cells: byrow.setdefault(r, {})[c] = t rows, head = [], [] for r in sorted(byrow): row = [byrow[r][c] for c in sorted(byrow[r])] m = re.fullmatch(r"(\*{0,2})\s*(\d{4})", row[0].strip()) if row else None if m and len(row) >= 6: vals = row[-4:] rows.append((m.group(2), "".join(row[1:-4]).replace(" ", ""), m.group(1), vals)) else: head.append(row) return rows, head def convert(folder): folder = Path(folder) hwp = next(folder.glob("*.hwp")) stem = hwp.stem apply = folder.name reg, seq = INFO[apply] blocks = read_blocks(hwp) title = f"{stem[:4]}년 {stem[4:6]} 적용" hdr = ( f"> 원문: {hwp.name} (대한건설협회, 게시 {reg}, 적용 {apply})\n" "> 변환: cak_hwp_md.py — HWP 본문에서 글 · 표 칸 좌표를 직접 읽음. HWP 에는 쪽 구분이 없어 쪽 표기 없음 · 원문 PDF 없음(쪽 그림 대조 불가) — " "표 값은 같은 공표일이 실린 다른 회차 PDF 와 기계 대조(cak_verify.py). 표 안 글자 사이 벌림은 붙여 씀.\n\n" ) # 장 나누기: 표 밖 문단 중 목차(탭 없는) 장 제목 idx = {} for i, b in enumerate(blocks): if b[0] == "p" and "\t" not in b[1]: n = re.sub(r"\s", "", b[1]) for name, key in CHAPTERS: if n == key and name not in idx: idx[name] = i order = [idx[n] for n, _ in CHAPTERS] assert order == sorted(order), idx bounds = order + [len(blocks)] def render(bs): out = [] for b in bs: if b[0] == "p": out.append(b[1] + " ") continue _, cells, rows, cols = b jr, head = jobs_table(cells) if len(jr) >= 10: # 개별직종 표 dates = [] for h in head: dates += [x for x in h if re.fullmatch(r"\d{4}\.\d{1,2}\.\d{1,2}", x.strip())] out.append("") out.append("| 직종코드 | 직종명 | 신뢰도 | " + " | ".join(dates[:4]) + " |") out.append("|---|---|---|---|---|---|---|") for c, n, f, v in jr: out.append(f"| {c} | {n} | {f} | " + " | ".join(esc(x) for x in v) + " |") out.append("") else: out.append("") out += md_grid(cells, rows, cols) out.append("") return out pre = render(blocks[: order[0]]) chapters = {} for j, (name, _) in enumerate(CHAPTERS): chapters[name] = render(blocks[bounds[j] : bounds[j + 1]]) full_md = ( f"# {title}\n\n> 원본: `{hwp.name}`\n\n" + "\n".join(pre + [x for n, _ in CHAPTERS for x in chapters[n]]) + "\n" ) (folder / f"{stem}.md").write_text(full_md, encoding="utf-8") for name, _ in CHAPTERS: (folder / f"{name}.md").write_text( f"# {name.split('. ', 1)[1]}\n\n{hdr}" + "\n".join(chapters[name]) + "\n", encoding="utf-8", ) return len([1 for b in blocks if b[0] == "t"]) if __name__ == "__main__": for f in sys.argv[1:]: print(f, "표", convert(f))