# -*- coding: utf-8 -*-
"""건설품셈 공통 제3장 md 읽기 · 표 만들기 · 쓰기 도구 (build_소요량_건설품셈_공통3장.py 가 씀)."""
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
SRC = (
ROOT / "resources/knowledge/original/원가계산/건설공사_표준품셈/본문/01_공통부문/제03장_토공사"
)
OUT = ROOT / "resources/master_data/소요량_건설품셈_공통3장.json"
DIV = "건설품셈 공통 "
class Raw(str):
"""원문 수 글자 그대로(0.040 유지)."""
NUMRE = re.compile(r"^\d[\d,]*(\.\d+)?$")
def N(x):
x = x.strip()
if not NUMRE.match(x):
raise ValueError(f"수 아님: {x!r}")
return Raw(x.replace(",", ""))
def R(x):
return Raw(x.replace(",", ""))
def join(cell):
parts = [p.strip() for p in cell.split("
")]
out = parts[0]
for p in parts[1:]:
out += ("" if out.endswith("∼") else " ") + p
return out
def unesc(s):
return re.sub(r"\\([\\*\-#>.|])", r"\1", s).replace("
", " ")
# ── md 읽기 ────────────────────────────────────────────────
class Tab:
def __init__(self, rows, base):
self.rows, self.base = rows, base
def body_lines(path):
lines = path.read_text(encoding="utf-8").split("\n")
at = [i for i, x in enumerate(lines) if x.strip() == "---"]
return lines[at[1] + 1 :]
def parse_tables(path):
L = body_lines(path)
out, i = [], 0
while i < len(L):
if not L[i].startswith("|"):
i += 1
continue
j = i
while j < len(L) and L[j].startswith("|"):
j += 1
rows = []
for ln in L[i:j]:
cells = [c.strip() for c in ln.strip().strip("|").split("|")]
if all(re.fullmatch(r":?-+:?", c) for c in cells):
continue
rows.append(cells)
k = i - 1
while k >= 0 and not L[k].strip():
k -= 1
m = re.fullmatch(r"\((.*)\)", L[k].strip()) if k >= 0 else None
out.append(Tab(rows, m.group(1) if m else ""))
i = j
return out
FILES = {p.name[:4]: p for p in sorted(SRC.glob("3-*.md"))}
TABS = {k: parse_tables(p) for k, p in FILES.items()}
def sec_lines(ident):
"""항 번호(3-2-1)의 본문 줄(제목 포함, 같은·윗 제목 전까지)."""
L = body_lines(FILES[f"3-{int(ident.split('-')[1]):02d}"])
for at, ln in enumerate(L):
m = re.match(rf"^(#+)\s*{re.escape(ident)}(\s|\(|$)", ln)
if m:
end = len(L)
for k in range(at + 1, len(L)):
h = re.match(r"^(#+)\s", L[k])
if h and len(h.group(1)) <= len(m.group(1)):
end = k
break
return L[at:end]
raise KeyError(ident)
def sec_text(ident):
return unesc("\n".join(sec_lines(ident)))
def notes(ident, n=0):
"""항의 n번째 [주] 묶음 줄들(원문 글)."""
blocks, cur = [], None
for ln in sec_lines(ident):
s = ln.strip()
if s == "[주]":
cur = []
blocks.append(cur)
continue
if cur is None:
continue
if re.match(r"^#", s) or s.startswith("[참고") or re.match(r"^[가-힣]\. ", s):
cur = None
continue
if not s or s.startswith(("|", "