Files
Aislo/resources/master_data/scripts/_토목_손.py
T
eomsangdonandClaude Sonnet 5 a09fbdfd78 feat(master_data): 건설 토목 1장 2장 6장 소요량 옮김
- 소요량_건설품셈_토목1장(116표) · 토목2장(9표) · 토목6장(73표) — md 표 73 · 8 · 50 개 모두 + 글 속 계수 표
- 변환 스크립트 build_소요량_건설품셈_토목.py + _토목_읽기 · _토목_표 · _토목_손 · _토목_계수
- check_master 틀 · 본문 · 로직 0건

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
2026-09-19 17:16:42 +09:00

205 lines
6.5 KiB
Python

# -*- coding: utf-8 -*-
"""토목 표 손 지정 — 칸 안에 줄이 여럿(<br>)이거나 줄마다 머리가 달라 자동으로 못 읽는 표. (build_소요량_건설품셈_토목.py 가 씀)"""
import re
from _md표_읽기 import N, R, join
from _토목_읽기 import is_num, nz
from _토목_표 import bigo_items, conds_out, crew, jn, matrix, members, rate, tpose
SPECIAL = {"1": {}, "2": {}, "6": {}}
def finish(rows, cols, bigo=(), label=None):
names = []
for r in rows:
for k in r:
if k not in names and k not in cols:
names.append(k)
return conds_out(names, rows), cols, rows, list(bigo), label
def sp(ch, key):
def deco(fn):
SPECIAL[ch][key] = fn
return fn
return deco
def lines(x):
return [p.strip() for p in x.split("<br>")]
# ── 제1장 ──────────────────────────────────────────────────────
sp("1", "1-8-9#4")(lambda t: (*tpose(t, "트럭", "작업"), None))
sp("1", "1-8-2#2")(lambda t: (*tpose(t, "형식", "크레인"), None))
sp("1", "1-8-14#2")(lambda t: (*rate(t), None))
@sp("1", "1-9-1#1")
def _(t):
R0, rows, cols = t.rows, [], {"시공량": "개소"}
heads = R0[2][5:8]
for lo, hi in ((3, 6), (6, 9)):
blk = R0[lo:hi]
c_, v = members(blk, 2, 1, 3)
cols.update(c_)
hts = lines(blk[0][4])
for j, hd in enumerate(heads):
vs = lines(blk[0][5 + j])
for i, hv in enumerate(hts):
if nz(vs[i]):
rows.append({"지주높이": hv, "지주 간격": hd, "시공량": N(vs[i]), **v})
return finish(rows, cols)
@sp("1", "1-9-1#2")
def _(t):
R0, rows, cols = t.rows, [], {"시공량": "개"}
heads = [jn(x) for x in R0[2][5:9]]
for lo, hi, hrows in ((3, 6, [3]), (6, 10, [6, 7, 8, 9])):
c_, v = members(R0[lo:hi], 2, 1, 3)
cols.update(c_)
for r in hrows:
for j, hd in enumerate(heads):
if nz(R0[r][5 + j]):
rows.append(
{
"지주높이": jn(R0[r][4]),
"방음벽 개당 면적": hd,
"시공량": N(R0[r][5 + j]),
**v,
}
)
return finish(rows, cols)
@sp("1", "1-9-2#0")
def _(t):
R0, rows, cols = t.rows, [], {"시공량": "m"}
for lo, hi in ((2, 5), (5, 8)):
blk = R0[lo:hi]
c_, v = members(blk, 3, 2, 4, 1)
cols.update(c_)
sizes = lines(blk[0][5])
for j, kind in enumerate((R0[1][6], R0[1][7])):
vs = lines(blk[0][6 + j])
for i, sz in enumerate(sizes):
rows.append(
{
"형식": jn(blk[0][0]),
"규격(아래폭+높이㎜)": sz,
"구간": kind,
"시공량": N(vs[i]),
**v,
}
)
return finish(rows, cols)
@sp("1", "1-9-4#2")
def _(t):
R0, rows, notes = t.rows, [], []
for row in R0[1:]:
if join(row[0]) == "산출기준":
notes = ["산출기준 " + x[len("비고 ") :] for x in bigo_items(row[1])]
continue
d = {"구분": jn(row[0]), "단위": row[1], "수량": N(row[2])}
if nz(row[3]):
d["비고"] = jn(row[3])
rows.append(d)
return conds_out(["구분"], rows), {"수량": "단위 칸 따름", "비고": "글"}, rows, notes, None
# ── 제6장 ──────────────────────────────────────────────────────
@sp("6", "6-1-1#0")
def _(t):
rows = []
for row in t.rows[2:]:
d = {"구분": jn(row[0]), "내용": jn(row[1])}
for nm, c in (("요율 품", 2), ("요율 시공량", 3)):
if nz(row[c]):
d[nm] = R(row[c].rstrip("%"))
rows.append(d)
return (
conds_out(["구분"], rows),
{"내용": "글", "요율 품": "%", "요율 시공량": "%"},
rows,
[],
None,
)
def multi(t):
"""칸 안에 관경 · 시공량이 줄줄이 든 [구분 단위 수량 관경 시공량] 표."""
R0, rows, cols, bigo = t.rows, [], {}, []
unit = re.search(r"\((.*)\)", join(R0[0][4])).group(1)
cols["시공량"] = unit
blocks = []
for row in R0[1:]:
if join(row[0]) == "비고":
bigo += bigo_items(row[1])
elif nz(row[3]):
blocks.append([row])
else:
blocks[-1].append(row)
for blk in blocks:
c_, v = members(blk, 1, None, 2)
cols.update(c_)
ds, vs = lines(blk[0][3]), lines(blk[0][4])
assert len(ds) == len(vs), (t.ident, ds, vs)
for d, x in zip(ds, vs):
rows.append({"관경(㎜)": d, "시공량": N(x), **v})
return conds_out(["관경(㎜)"], rows), cols, rows, bigo, None
for k in (
"6-2-1#0",
"6-2-1#1",
"6-2-2#0",
"6-2-2#1",
"6-3-1#0",
"6-3-1#1",
"6-4-1#0",
"6-4-2#0",
"6-5-1#0",
"6-5-2#0",
"6-5-3#0",
"6-5-4#0",
"6-6-1#0",
"6-6-2#0",
):
SPECIAL["6"][k] = multi
sp("6", "6-2-2#2")(lambda t: (*rate(t), None))
sp("6", "6-5-4#1")(lambda t: (*rate(t), None))
sp("6", "6-8-5#2")(lambda t: (*rate(t), None))
sp("6", "6-8-4#2")(lambda t: (*matrix(t, "본관", "지관", "중량", "㎏", 2), None))
sp("6", "6-7-5#0")(lambda t: (*crew(t, prefix_group=True), None))
@sp("6", "6-3-2#0")
def _(t):
R0, rows, cols = t.rows, [], {"시공량": "개소", "용접공": "인"}
heads = [
(jn(R0[0][4]), jn(R0[1][4]), jn(R0[2][4])),
(None, jn(R0[1][4]), jn(R0[2][5])),
(None, jn(R0[1][6]), jn(R0[2][6])),
]
combos = [(4, "A종", "겹치기 용접"), (5, "A종", "베벨엔드용접"), (6, "B종", "겹치기 용접")]
for r in R0[3:]:
if nz(r[0]):
qty = N(r[2])
for c, a, b in combos:
if nz(r[c]):
rows.append(
{
"관경(㎜)": jn(r[3]),
"종별": a,
"용접방법": b,
"시공량": N(r[c]),
"용접공": qty,
}
)
return conds_out(["관경(㎜)", "종별", "용접방법"], rows), cols, rows, [], None