merge: origin/sub_laptop_2 합류 — 9장 계수 표 합집합(양쪽 열쇠 모두 살림) · 9장 소요량 식 값 반영

This commit is contained in:
2026-09-19 16:22:29 +09:00
6 changed files with 7036 additions and 470 deletions
@@ -0,0 +1,639 @@
"""건설품셈 공통 제8장 8-3(손료) · 8-4(운전경비) · 8-5(기계가격) 표 → resources/master_data/기계_건설품셈.json
본문 md(확정) 표를 읽어 기계 한 줄로 합침. 값은 md 에서만 · 계산·추정 없음.
실행: python resources/master_data/scripts/build_기계_건설품셈.py [--dry]
"""
import json
import re
import sys
from pathlib import Path
REPO = Path(__file__).resolve().parents[3]
DIR = (
REPO
/ "resources/knowledge/original/원가계산/건설공사_표준품셈/본문/01_공통부문/제08장_건설기계"
)
OUT = REPO / "resources/master_data/기계_건설품셈.json"
SRC = "건설품셈 공통 "
NUM = re.compile(r"^-?\d+(?:,\d{3})*(?:\.\d+)?$")
# ---------------------------------------------------------------- md 읽기
def cell_join(s, name=False):
"""<br> 줄바꿈 이음. 숫자·연산자 사이는 붙이고 그 밖은 한 칸."""
parts = s.split("<br>")
out = parts[0].strip()
for p in parts[1:]:
p = p.strip()
if not out or not p:
out += p
continue
a, b = out[-1], p[0]
if (a.isdigit() and b.isdigit()) or b in "×)" or a in "(×∼~" or (name and b == "("):
out += p
else:
out += " " + p
return out
def read_md(path):
"""표 목록 [{h3, h4, rows, notes}] — rows 는 구분줄 뺀 셀 목록."""
L = path.read_text(encoding="utf8").split("\n")
L = L[L.index("---", 1) + 1 :]
tabs, h3, h4, i = [], "", "", 0
while i < len(L):
ln = L[i]
if ln.startswith("### "):
h3, h4 = ln[4:].strip(), ""
elif ln.startswith("#### "):
h4 = ln[5:].strip()
elif ln.startswith("|"):
rows = []
while i < len(L) and L[i].startswith("|"):
if not re.match(r"^\|[\s\-|:]+\|$", L[i]):
rows.append([c.strip() for c in L[i].strip()[1:-1].split("|")])
i += 1
notes, comments = [], []
while i < len(L) and not L[i].startswith(("#", "|")):
t = L[i].strip()
if t.startswith("<!--"):
comments.append(t)
elif t:
notes.append(t.replace("\\*", "*"))
i += 1
tabs.append(
{
"h3": h3,
"h4": h4,
"rows": rows,
"notes": notes,
"comments": comments,
"file": path.name,
}
)
continue
i += 1
return tabs
def num(s):
"""쉼표 뺀 수 · '-' 와 빈칸은 None · 그 밖 글은 그대로."""
s = s.strip()
if s in ("", "-"):
return None
if NUM.match(s):
t = s.replace(",", "")
f = float(t)
return int(f) if f == int(f) and "." not in t else float(t)
return s
def sec_no(h3):
return h3.split()[0] # '8-3-1'
def full_code(raw, prefix):
raw = raw.strip()
if re.fullmatch(r"\d{4}-\d{4}", raw):
return raw, raw[:4]
if re.fullmatch(r"-?\d{4}", raw) and prefix: # 원문에 「-0003」 꼴도 있음
return f"{prefix}-{raw.lstrip('-')}", prefix
return None, prefix
# ---------------------------------------------------------------- 8-3
def unit_of(label):
m = re.search(r"\(([^()]*)\)$", label)
return m.group(1) if m else None
def build_83(tabs, rows_out, tables_out, notes_out, anomalies):
for t in tabs:
h1 = t["rows"][0]
c1 = [cell_join(c) for c in h1]
code = re.match(r"\((\d{4})\)", t["h4"])
code = code.group(1) if code else None
key_note = f"{sec_no(t['h3'])} ({code})"
if c1[0].replace(" ", "") == "공기압축기":
tables_out.append(("관계", t, key_note))
notes_out.setdefault(key_note, []).extend(t["notes"])
continue
has2 = len(t["rows"]) > 1 and t["rows"][1][0] == ""
c2 = [cell_join(c) for c in t["rows"][1]] if has2 else None
data = t["rows"][2:] if has2 else t["rows"][1:]
H = [c.replace(" ", "") for c in c1]
iN = next((i for i, h in enumerate(H) if h.startswith("내용")), None)
iS = next(i for i, h in enumerate(H) if h.startswith("시간당"))
sp_end = iN if iN is not None else iS
spec = [] # (index, label)
for i in range(1, sp_end):
lab = (c2[i] if c2 and c2[i] else c1[i]).replace(" ", "")
if c2 is None and lab == "규격" and i > 1 and c1[i - 1] and False:
pass
spec.append((i, lab))
mid = [(i, H[i]) for i in range(sp_end, iS)]
if c2:
sons = [(i, c2[i].replace(" ", "")) for i in range(iS, len(c1))]
else:
sons = [(iS, "손료계수")]
sons = [(i, "손료계수" if l == "" else l) for i, l in sons]
merged = {
i
for i in range(1, len(c1))
if any(re.search(rf"병합: {i + 1}\d+~\d+행", c) for c in t["comments"])
}
prefix, inherit, group = None, {}, ""
for r in data:
r = r + [""] * (len(c1) - len(r))
raw = r[0].strip()
if re.fullmatch(r"\d{4}-", raw): # 「9020-」 접두 줄
prefix = raw[:4]
group = " ".join(cell_join(r[i], True) for i, _ in spec if r[i].strip())
continue
fc, prefix = full_code(raw, prefix)
if not fc:
anomalies.append(f"8-3 코드 해석 실패 {t['file']} {raw!r}")
continue
parts, appended = ([group] if group else []), False
for i, lab in spec:
if r[i].strip():
inherit[i] = v = cell_join(r[i])
else:
v = inherit.get(i, "") if i in merged else ""
if not v:
continue
u = unit_of(lab)
base = re.sub(r"\(.*", "", lab) if "(" in lab else lab
if len(spec) == 1:
simple = u and lab.count("(") == 1
appended = bool(simple and NUM.match(v.replace(",", "")))
parts.append(v + u if appended else v)
else:
parts.append(f"{base} {v}{u if u and NUM.match(v.replace(',', '')) else ''}")
unit_note = None
if len(spec) == 1 and not appended and unit_of(spec[0][1]):
unit_note = re.sub(r"^규격", "", spec[0][1])
elif len(spec) > 1 and any(unit_of(lab) for _, lab in spec):
unit_note = " · ".join(lab for _, lab in spec)
vals, odd = {}, {}
for i, lab in mid + sons:
n = num(r[i])
if isinstance(n, str) and re.fullmatch(
r"\d[\d,]*", n
): # 쉼표 자리가 어긋난 원문(3,0000)
odd[f"{sec_no(t['h3'])} {lab}"] = n
n = int(n.replace(",", ""))
vals[lab] = n
rows_out.setdefault(fc, {}).update(
{
"이름83": re.sub(r"\s*\('\d\d[^()]*\)$", "", t["h4"])
.split(") ", 1)[-1]
.strip(),
"규격": " · ".join(parts),
"규격단위": unit_note,
"83": vals,
"원문83": odd or None,
"sec83": sec_no(t["h3"]),
}
)
notes_out.setdefault(key_note, []).extend(t["notes"])
# ---------------------------------------------------------------- 8-4 (분류번호 줄 표)
def parse_fuel(s):
"""주연료 칸 → (값, 종류, 원문표시 필요)"""
raw = cell_join(s)
if raw in ("", "-"):
return None, None, False
m = re.fullmatch(r"(휘발유|중유|경유)\s*(\d+(?:\.\d+)?)", raw)
if m:
return num(m.group(2)), m.group(1), True
if NUM.match(raw.replace(",", "")):
return num(raw), "경유", False
return raw, None, True
def build_84(tabs, rows_out, notes_out, anomalies):
for t in tabs:
H = [cell_join(c).replace(" ", "") for c in t["rows"][0]]
if H[0] != "분류번호":
continue
prefix, name = None, ""
sec = sec_no(t["h3"])
for r in t["rows"][1:]:
fc, prefix = full_code(r[0], prefix)
if not fc:
anomalies.append(f"8-4 코드 해석 실패 {r[0]!r}")
continue
if r[1].strip():
name = cell_join(r[1], True)
fuel, kind, orig = parse_fuel(r[3])
jam = r[4].strip().rstrip("%")
op = num(r[5])
rows_out.setdefault(fc, {}).update(
{
"이름84": name,
"규격84": cell_join(r[2]),
"84": {
"주연료": fuel,
"주연료종류": kind,
"잡재료율": num(jam) if jam else None,
"조종원": op,
},
"원문84": {
k: v
for k, v in (
("주연료", cell_join(r[3]) if orig else None),
("잡재료", cell_join(r[4]) if isinstance(num(jam), str) else None),
)
if v
}
or None,
"sec84": sec,
}
)
notes_out.setdefault(sec, []).extend(t["notes"])
# ---------------------------------------------------------------- 8-4-9 해상 (가로 표)
def build_849(tabs, rows_out, notes_out, anomalies):
for t in tabs:
H = [cell_join(c).replace(" ", "") for c in t["rows"][0]]
if H[0] != "명칭":
continue
m = re.match(r"\((\d{4})\)", t["h4"])
grp = m.group(1)
sec = sec_no(t["h3"])
specs = [cell_join(c) for c in t["rows"][1][2:-1]]
cols = sorted(k for k, v in rows_out.items() if k.startswith(grp + "-") and "83" in v)
if len(cols) != len(specs):
anomalies.append(f"8-4-9 {grp}{len(specs)} ≠ 8-3 줄 {len(cols)}")
continue
# 규격 글의 수와 8-3 규격 수가 같은 순서인지 눈으로 볼 수 있게 남김
for k, s in zip(cols, specs):
a = re.findall(r"\d+(?:,\d{3})*(?:\.\d+)?", s)
b = re.findall(r"\d+(?:,\d{3})*(?:\.\d+)?", rows_out[k]["규격"])
if not (set(a) & set(b) or not a):
anomalies.append(
f"8-4-9 {grp} 열-줄 대응 의심 {k} 84={s!r} 83={rows_out[k]['규격']!r}"
)
for ci, k in enumerate(cols):
v84 = {"주연료": None, "주연료종류": None, "잡재료율": None, "조종원": None}
extra, orig = {}, {}
for r in t["rows"][2:]:
lab = cell_join(r[0]).replace(" ", "")
cell = cell_join(r[2 + ci])
if lab == "주연료":
val = num(cell)
v84["주연료"] = val
v84["주연료종류"] = "경유" if isinstance(val, (int, float)) else None
elif lab == "잡재료":
val = num(cell)
v84["잡재료율"] = val
if isinstance(val, str):
orig["잡재료"] = cell_join(cell)
elif lab in ("준설선운전사", "건설기계운전사"):
v84["조종원"] = num(cell)
v84["조종원직종"] = "1054" if lab == "준설선운전사" else "1048"
else:
extra[lab] = num(cell)
rows_out[k].update(
{
"이름84": rows_out[k]["이름83"],
"84": v84,
"extra84": extra,
"원문84": orig or None,
"sec84": sec,
"직종고정": "조종원직종" in v84 and v84.get("조종원직종") is not None,
}
)
notes_out.setdefault(f"{sec} ({grp})", []).extend(t["notes"])
# ---------------------------------------------------------------- 8-5
def build_85(tabs, rows_out, anomalies):
for t in tabs:
H = [cell_join(c).replace(" ", "") for c in t["rows"][0]]
if H[0] != "기종":
continue
prefix, name = None, ""
for r in t["rows"][1:]:
if r[0].strip():
name = cell_join(r[0], True)
fc, prefix = full_code(r[1], prefix)
if not fc:
anomalies.append(f"8-5 코드 해석 실패 {r[1]!r}")
continue
p = num(r[2])
if not isinstance(p, int):
anomalies.append(f"8-5 가격 이상 {fc} {r[2]!r}")
rows_out.setdefault(fc, {}).update(
{"이름85": name, "가격": p, "sec85": sec_no(t["h3"])}
)
# ---------------------------------------------------------------- 조종원 직종 (8-1-3 5 에 이름이 나온 기종만)
K1048 = [
"불도저",
"굴착기",
"굴삭기",
"로더",
"지게차",
"스크레이퍼",
"모터그레이더",
"롤러",
"스테이빌라이저",
"노상안정기",
"배치플랜트",
"피니셔",
"스프레더",
"아스팔트믹싱플랜트",
"골재살포기",
"슬러리실",
"천공기",
"사리채취기",
"노면파쇄기",
]
K1049 = ["살수차", "화물트럭", "트랙터", "제설차", "노면청소차", "트럭탑재형크레인"]
K1050 = ["양수기", "윈치", "발전기", "래머", "콤팩터", "벨트컨베이어", "콘크리트파쇄기"]
JOB_NAME = {
"1048": "건설기계운전사",
"1049": "화물차운전사",
"1050": "일반기계운전사",
"1054": "준설선운전사",
}
def job_of(name):
n = re.sub(r"\s", "", name)
for k, code in ((K1048, "1048"), (K1049, "1049"), (K1050, "1050")):
if any(w in n for w in k):
return code
return None
def job_for_row(name, spec):
n = re.sub(r"\s", "", name)
m = re.match(r"\d+(?:\.\d+)?", spec.replace(",", ""))
q = float(m.group(0)) if m else None
if "덤프트럭" in n:
return None if q is None else ("1048" if q >= 12 else "1049")
if "공기압축기" in n and "이동식" in n:
return "1048" if q is not None and q >= 2.83 else None
return job_of(name)
# ---------------------------------------------------------------- 실행
def load():
t83, t84, t85 = [], [], []
for p in sorted(DIR.glob("8-03-0[1-9]*.md")) + sorted(DIR.glob("8-03-10*.md")):
t83 += read_md(p)
t84 = read_md(next(DIR.glob("8-04_*.md")))
t85 = read_md(next(DIR.glob("8-05_*.md")))
return t83, t84, t85
UNIT = {
"가격": "천원",
"내용시간": "시간",
"연간표준가동시간": "시간",
"상각비율": "",
"정비비율": "",
"연간관리비율": "",
"상각비계수": "10^-7/시간",
"정비비계수": "10^-7/시간",
"관리비계수": "10^-7/시간",
"손료계수": "10^-7/시간",
"주연료": "/hr",
"주연료종류": "",
"잡재료율": "주연료의 %",
"조종원": "인/일",
"조종원직종": "",
}
K83 = [
"내용시간",
"연간표준가동시간",
"상각비율",
"정비비율",
"연간관리비율",
"상각비계수",
"정비비계수",
"관리비계수",
"손료계수",
]
FUEL_NOTE = SRC + "8-4 주①㉰"
def note_lines(lines):
out = []
for ln in lines:
ln = re.sub(r"^\[주\]\s*", "", ln)
if ln:
out.append(ln)
return out
def compose(rows):
out = []
for k in sorted(rows):
v = rows[k]
r83, r84 = v.get("83"), v.get("84")
name = v.get("이름83") or v.get("이름84") or v.get("이름85")
spec = v.get("규격") or v.get("규격84") or ""
# 값이 null 인 칸의 출처 = 그 칸을 읽는 절(틀 검사가 출처 문자열을 요구) · 표에 줄이 있으면 그 표의 절
s83, s84 = SRC + v.get("sec83", "8-3"), SRC + v.get("sec84", "8-4")
val = {"가격": v.get("가격")}
src = {"가격": SRC + v.get("sec85", "8-5")}
for f in K83:
val[f] = (r83 or {}).get(f)
src[f] = s83
for f in ("주연료", "주연료종류", "잡재료율", "조종원"):
val[f] = (r84 or {}).get(f)
src[f] = FUEL_NOTE if f == "주연료종류" and val[f] == "경유" else s84
fixed = (r84 or {}).get("조종원직종")
job = fixed or (job_for_row(name, spec) if val["조종원"] is not None else None)
val["조종원직종"] = job
src["조종원직종"] = SRC + "8-1-3 5" + (" · 건설노임 " + job if job else "")
for lab, x in (v.get("extra84") or {}).items():
val[lab] = x
src[lab] = s84
unit = dict(UNIT)
for lab in v.get("extra84") or {}:
unit[lab] = ""
row = {"열쇠": k, "이름": name, "규격": spec, "단위": unit, "": val, "출처": src}
memo = ["조종원직종 원문 이름: " + JOB_NAME[job]] if job else []
if v.get("규격단위"):
memo.append("규격 단위: " + v["규격단위"])
if memo:
row["비고"] = " · ".join(memo)
org = dict(v.get("원문83") or {})
org.update({f"{v['sec84']} {a}": b for a, b in (v.get("원문84") or {}).items()})
if org:
row["원문"] = org
out.append(row)
return out
def dumps_row(r):
j = lambda o: json.dumps(o, ensure_ascii=False)
head = f'{{ "열쇠": {j(r["열쇠"])}, "이름": {j(r["이름"])}, "규격": {j(r["규격"])},'
tail = [k for k in ("비고", "원문") if k in r]
body = [f' "단위": {j(r["단위"])},', f' "": {j(r[""])},']
body.append(f' "출처": {j(r["출처"])}' + ("," if tail else " }"))
for n, k in enumerate(tail):
body.append(f' "{k}": {j(r[k])}' + ("," if n < len(tail) - 1 else " }"))
return " " + head + "\n" + "\n".join(body)
# ---------------------------------------------------------------- 관계표 · 글 속 계산용 수
def relation_table(t, key):
R = t["rows"]
grp = [cell_join(c) for c in R[0]]
spec = [cell_join(c) for c in R[1]]
hose = [cell_join(c) for c in R[2]]
names, cur = [], ""
for j in range(2, len(R[0])):
if grp[j]:
cur = grp[j]
names.append(f"{cur} {spec[j]}".strip())
lines = []
for r in R[3:]:
size = num(r[0])
for j, nm in enumerate(names, start=2):
c = cell_join(r[j]) if j < len(r) else ""
if c in ("", "-"):
continue
m = re.fullmatch(r"(\d+)\((\d+)\)", c)
row = {"공기압축기 규격": size, "부수물": nm}
if hose[j].strip():
row["사용에어호스경"] = num(hose[j])
row["사용가능대수"] = int(m.group(1)) if m else num(c)
if m:
row["괄호값"] = int(m.group(2))
lines.append(row)
return {
"열쇠": f"8-3-6 ({key[-5:-1]}) 공기압축기·부수물 관계",
"이름": "공기압축기 규격별 부수물 사용가능 대수",
"그룹": "계수",
"기준": "",
"출처": SRC + "8-3-6 (5210)",
"조건": {"공기압축기 규격": "", "부수물": "고르기", "사용에어호스경": ""},
"값칸": {"사용가능대수": "", "괄호값": "대(수중 4m 이하)"},
"": lines,
"": t["notes"],
}
def text_tables(notes):
def tb(key, name, src, cond, vc, lines, note):
return {
"열쇠": key,
"이름": name,
"그룹": "계수",
"기준": "",
"출처": SRC + src,
"조건": cond,
"값칸": vc,
"": lines,
"": note,
}
n83 = notes["8-3-3 (2208)"]
n84 = notes["8-4-8"]
g = lambda L, s: next(x for x in L if x.startswith(s))
return [
tb(
"8-3-3 (2208) 주③ 권상용 와이어",
"타워크레인 권상용 와이어 소모",
"8-3-3 (2208) 주③",
{"구분": "고르기"},
{"": "", "단위": ""},
[
{"구분": "와이어 규격", "": "18㎜×120m", "단위": "1set"},
{"구분": "시간당 소모율", "": 0.003, "단위": "1set 기준"},
],
[g(n83, "")],
),
tb(
"8-3-3 (2210) 주③ 동력",
"건설용리프트 동력",
"8-3-3 (2210) 주③",
{"구분": "고르기"},
{"": "", "대수": ""},
[{"구분": "동력", "": 7.5, "대수": 2}],
[g(notes["8-3-3 (2210)"], "")],
),
tb(
"8-4 주①㉮ 연료 소비량 산정 기준",
"시간당 주연료 소비량 산정 기준",
"8-4 주①㉮",
{"구분": "고르기"},
{"최소": "%", "최대": "%", "적용식": ""},
[
{"구분": "엔진부하율", "최소": 70, "최대": 80},
{"구분": "실작업시간", "적용식": "50/60", "원문": "실작업시간은 50/60"},
],
[g(n84, "")],
),
tb(
"8-4 주⑤ 잡재료 비율",
"불도저·굴착기 부착기계 조합 시 잡재료 비율",
"8-4 주⑤",
{"구분": "고르기"},
{"": "주연료의 %"},
[{"구분": "불도저 및 굴착기에 리퍼·브레이커·부착용집게 조합", "": 16}],
[g(n84, "")],
),
]
def main():
t83, t84, t85 = load()
rows, special, notes, anom = {}, [], {}, []
build_83(t83, rows, special, notes, anom)
build_84(t84, rows, notes, anom)
build_849(t84, rows, notes, anom)
build_85(t85, rows, anom)
body = compose(rows)
tables = [relation_table(t, key) for _, t, key in special] + text_tables(notes)
jn = {k: note_lines(v) for k, v in notes.items() if note_lines(v)}
j = lambda o, ind=None: json.dumps(o, ensure_ascii=False, indent=ind)
parts = [
'{\n "그룹": "기계",\n "원문": "건설품셈",\n "": "2026",\n',
' "": ' + json.dumps(jn, ensure_ascii=False, indent=2).replace("\n", "\n ") + ",\n",
' "": [\n' + ",\n".join(dumps_row(r) for r in body) + "\n ],\n",
' "": '
+ json.dumps(tables, ensure_ascii=False, indent=2).replace("\n", "\n ")
+ "\n}\n",
]
text = "".join(parts)
json.loads(text)
return text, rows, body, anom, tables, jn
if __name__ == "__main__":
text, rows, body, anom, tables, jn = main()
for a in anom:
print("이상:", a)
print("기계", len(body), "", len(tables), "주 묶음", len(jn), "줄수", text.count("\n"))
if "--dry" not in sys.argv:
with open(OUT, "w", encoding="utf8", newline="\n") as f:
f.write(text)
print("", OUT)
@@ -0,0 +1,368 @@
{
"그룹": "계수",
"원문": "산림품셈",
"판": "2026-01-01",
"표": [
{
"열쇠": "13-2-1 주 계산용 수",
"이름": "채집 인력 주 속 수",
"기준": "",
"출처": "산림품셈 13-2-1 주②④",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "선별기 보조원 보통인부(기계채집)", "적용": [2, 3], "단위": "인/대당", "적용원문": "23인/대당" },
{ "구분": "석재 세척 유해물질 초과 시 보통인부 할증", "적용": 0.2, "단위": "인" }
],
"주": []
},
{
"열쇠": "13-2-2 소할 할증",
"이름": "막돌 채집 소할 할증",
"기준": "",
"출처": "산림품셈 13-2-2",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "전석 소할 시 할석공 할증", "적용": 0.2, "단위": "인/㎥", "적용원문": "㎥당 할석공 0.2인을 할증한다" }
],
"주": []
},
{
"열쇠": "13-2-3 주 계산용 수",
"이름": "큰돌 채집 주 속 계산용 수",
"기준": "",
"출처": "산림품셈 13-2-3 주②③④⑦⑧⑨⑩",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "큰돌 직경 범위", "적용": [40, 100], "단위": "㎝", "적용원문": "직경 40㎝이상~100㎝이하" },
{ "구분": "큰돌 뒷길이 범위", "적용": [60, 120], "단위": "㎝", "적용원문": "뒷길이 60120㎝" },
{ "구분": "돌 구입 운반 공극률", "적용": 23, "단위": "%" },
{ "구분": "직경 60㎝ 이상 큰돌 최소화 기준", "적용": 60, "단위": "㎝" },
{ "구분": "소운반 포함 거리", "적용": 20, "단위": "m" },
{ "구분": "티스 소모율", "적용": 0.002 },
{ "구분": "티스갯수", "적용": 6, "단위": "개" },
{ "구분": "40㎝이상~60㎝미만 적용", "적용": 75, "단위": "%", "적용원문": "본품의 75%" },
{ "구분": "60㎝이상~80㎝미만 적용", "적용": 100, "단위": "%", "적용원문": "본품의 100%" },
{ "구분": "80㎝이상~100㎝이하 적용", "적용": 125, "단위": "%", "적용원문": "본품의 125%" },
{ "구분": "공사 시 발생하는 큰 돌 적용", "적용": 50, "단위": "%", "적용원문": "본 품의 50%" }
],
"주": []
},
{
"열쇠": "13-2-4 주① 소할 할증",
"이름": "야면석 채집 소할 할증",
"기준": "",
"출처": "산림품셈 13-2-4 주①",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "전석 소할 시 할석공 할증", "적용": 0.2, "단위": "인/㎥", "적용원문": "㎥당 할석공 0.2인을 할증한다" }
],
"주": []
},
{
"열쇠": "13-4-2 주③ 적용 조건",
"이름": "메쌓기(장비) 적용 조건",
"기준": "",
"출처": "산림품셈 13-4-2 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "경사도", "적용": "1:1", "적용원문": "1:1보다 급한 경우" },
{ "구분": "높이(이하)", "적용": 3, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-4-5 주③ 적용 조건",
"이름": "찰쌓기(장비) 적용 조건",
"기준": "",
"출처": "산림품셈 13-4-5 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "경사도", "적용": "1:1", "적용원문": "1:1보다 급한 경우" },
{ "구분": "높이(이하)", "적용": 3, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-4-6 주③ 적용 조건",
"이름": "밑돌 및 천단 돌쌓기 적용 조건",
"기준": "",
"출처": "산림품셈 13-4-6 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "높이(이하)", "적용": 3, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-4-4 주 계산용 수",
"이름": "찰쌓기 주 속 계산용 수",
"기준": "",
"출처": "산림품셈 13-4-4 주④⑤⑥⑦⑨",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "줄눈메꿈 모르타르", "적용": 0.009, "단위": "㎥" },
{ "구분": "물구멍 설치 면적당 1개소 이상", "적용": [2, 3], "단위": "㎡", "적용원문": "23㎡당 1개소 이상" },
{ "구분": "물구멍 파이프 지름", "적용": [3, 6], "단위": "㎝", "적용원문": "36㎝" },
{ "구분": "돌쌓기·돌붙이기 구분 경사도", "적용": "1:1" },
{ "구분": "절토 뒤채움 조약돌 두께(상·하부 같이)", "적용": [30, 40], "단위": "㎝", "적용원문": "3040㎝" }
],
"주": []
},
{
"열쇠": "13-5-1 주 계산용 수",
"이름": "돌붙임(인력) 주 속 수",
"기준": "",
"출처": "산림품셈 13-5-1 주③④",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "줄눈메꿈 모르타르", "적용": 0.009, "단위": "㎥/㎡" },
{ "구분": "돌붙임 틈메우기돌(고임돌량의 최대)", "적용": 15, "단위": "%" }
],
"주": []
},
{
"열쇠": "13-5-2 주③ 적용 조건",
"이름": "돌붙임(장비) 적용 조건",
"기준": "",
"출처": "산림품셈 13-5-2 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "경사도", "적용": "1:1", "적용원문": "1:1보다 완만한 경우" },
{ "구분": "높이(이하)", "적용": 5, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-6-1 주 계산용 수",
"이름": "큰돌 메쌓기 주 속 수",
"기준": "",
"출처": "산림품셈 13-6-1 주⑤⑨",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "사용 돌 직경(이하, 임도)", "적용": 60, "단위": "㎝" },
{ "구분": "소운반 포함 거리", "적용": 20, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-6-2 주 계산용 수",
"이름": "큰돌 찰쌓기 주 속 수",
"기준": "",
"출처": "산림품셈 13-6-2 주⑤⑩⑫",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "사용 돌 직경(이하, 임도)", "적용": 60, "단위": "㎝" },
{ "구분": "뒤채움콘크리트량 기준", "적용": 0.2, "단위": "㎥" },
{ "구분": "뒤채움콘크리트량 현지여건 상한", "적용": 0.3, "단위": "㎥" },
{ "구분": "소운반 포함 거리", "적용": 20, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-6-3 주 계산용 수",
"이름": "친환경 큰돌쌓기 주 속 수",
"기준": "",
"출처": "산림품셈 13-6-3 주⑤⑩",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "뒤채움콘크리트량 기준", "적용": 0.2, "단위": "㎥" },
{ "구분": "뒤채움콘크리트량 현지여건 상한", "적용": 0.3, "단위": "㎥" },
{ "구분": "소운반 포함 거리", "적용": 20, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-7-1 주⑤ 소운반",
"이름": "큰돌 메붙이기 소운반",
"기준": "",
"출처": "산림품셈 13-7-1 주⑤",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "소운반 포함 거리", "적용": 20, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-7-2 주⑤ 소운반",
"이름": "큰돌 찰붙이기 소운반",
"기준": "",
"출처": "산림품셈 13-7-2 주⑤",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "소운반 포함 거리", "적용": 20, "단위": "m" }
],
"주": []
},
{
"열쇠": "13-8 막돌쌓기 주 계산용 수",
"이름": "막돌쌓기 계산용 수",
"기준": "",
"출처": "산림품셈 13-8 머리 글 · 주④⑤",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "막돌 직경길이(이상)", "적용": 20, "단위": "㎝" },
{ "구분": "막돌 뒷길이", "적용": [25, 40], "단위": "㎝", "적용원문": "2540㎝" },
{ "구분": "높이(미만 불가 기준)", "적용": 2.0, "단위": "m", "적용원문": "2.0m 이상으로 할 수 없음" },
{ "구분": "막돌 붙임 적용", "적용": 70, "단위": "%", "적용원문": "본 품의 70%" }
],
"주": []
},
{
"열쇠": "13-10-2 말뚝박기 계산용 수",
"이름": "말뚝박기공 할증 · 감 계수",
"기준": "",
"출처": "산림품셈 13-10-2 머리 글 · 1 주①②③④ · 2 주①②③⑤ · 3 주①②④⑤⑧",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "산지 비탈면 시공 할증", "적용": 30, "단위": "%" },
{ "구분": "작은 말뚝 연토 지질 감", "적용": 20, "단위": "%" },
{ "구분": "작은 말뚝 자갈층 할증", "적용": 30, "단위": "%" },
{ "구분": "작은 말뚝 말뚝머리 자르기 보통인부 할증", "적용": 0.02, "단위": "인/본", "적용원문": "본당 보통인부 0.02인" },
{ "구분": "작은 말뚝 9할박기 할증", "적용": 30, "단위": "%" },
{ "구분": "작은 말뚝 말뚝빼기", "적용": 70, "단위": "%" },
{ "구분": "기초말뚝 사항박기 가산", "적용": 15, "단위": "%" },
{ "구분": "기초말뚝 말뚝빼기", "적용": 70, "단위": "%" },
{ "구분": "기초말뚝 연토사질 감", "적용": 20, "단위": "%" },
{ "구분": "기초말뚝 자갈질 가산", "적용": 30, "단위": "%" },
{ "구분": "기초말뚝 철근 콘크리트 말뚝박기 감", "적용": 30, "단위": "%" },
{ "구분": "윈치 보통 토사질 관입길이(박기)", "적용": [6, 8], "단위": "할", "적용원문": "68할" },
{ "구분": "윈치 35할 박기 개수 가산", "적용": 20, "단위": "%" },
{ "구분": "윈치 지질 가감(이내)", "적용": 30, "단위": "%" },
{ "구분": "윈치 콘크리트 말뚝 시공개수 가산", "적용": 20, "단위": "%" },
{ "구분": "윈치 원동기 전력 사용 시", "적용": 0.75, "단위": "KWH/HP/hr" },
{ "구분": "윈치 계항 선타항 길이 품 가산", "적용": 50, "단위": "%" }
],
"주": []
},
{
"열쇠": "13-11-1 주 계산용 수",
"이름": "원형 돌망태 주 속 수",
"기준": "",
"출처": "산림품셈 13-11-1 주④⑤",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "필터매트(부직포) 설치 시 특별인부", "적용": 0.09, "단위": "인/㎡" },
{ "구분": "필터매트(부직포) 설치 시 보통인부", "적용": 0.15, "단위": "인/㎡" },
{ "구분": "돌망태 간격가수(1연당)", "적용": 0.05, "단위": "m" },
{ "구분": "조약돌 크기(망태지름 대비, 미만)", "적용": "1/2" }
],
"주": []
},
{
"열쇠": "13-11-2 주 계산용 수",
"이름": "타원형 돌망태 주 속 수",
"기준": "",
"출처": "산림품셈 13-11-2 주④⑤",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "필터매트(부직포) 설치 시 특별인부", "적용": 0.09, "단위": "인/㎡" },
{ "구분": "필터매트(부직포) 설치 시 보통인부", "적용": 0.15, "단위": "인/㎡" },
{ "구분": "돌망태 간격가수(1연당)", "적용": 0.05, "단위": "m" },
{ "구분": "조약돌 크기(망태지름 대비, 미만)", "적용": "1/2" }
],
"주": []
},
{
"열쇠": "13-11-3 주 계산용 수",
"이름": "매트리스형 돌망태 주 속 수",
"기준": "",
"출처": "산림품셈 13-11-3 주③④⑤",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "필터매트(부직포) 설치 시 특별인부", "적용": 0.09, "단위": "인/㎡" },
{ "구분": "필터매트(부직포) 설치 시 보통인부", "적용": 0.15, "단위": "인/㎡" },
{ "구분": "매트리스형 폭", "적용": 100, "단위": "㎝" },
{ "구분": "매트리스형 높이", "적용": 30, "단위": "㎝" },
{ "구분": "굴착기(0.7㎥)", "적용": 0.012, "단위": "hr/㎥" }
],
"주": []
},
{
"열쇠": "13-12-2 지오셀 기준",
"이름": "지오셀 표준 사면",
"기준": "",
"출처": "산림품셈 13-12-2 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "표준 사면높이", "적용": 4, "단위": "m" },
{ "구분": "표준 기울기", "적용": "1:2" }
],
"주": []
},
{
"열쇠": "13-13-1 구조 구분",
"이름": "목재 구조 구분 기준",
"기준": "",
"출처": "산림품셈 13-13-1 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "보통구조 통나무 등 비율(이상)", "적용": 80, "단위": "%" },
{ "구분": "중등구조 통나무 등 비율(이상)", "적용": 50, "단위": "%" },
{ "구분": "상등구조 소각재 등 비율(이상)", "적용": 50, "단위": "%" }
],
"주": []
},
{
"열쇠": "13-14 식생토낭 주 계산용 수",
"이름": "식생토낭 및 포트",
"기준": "",
"출처": "산림품셈 13-14 주①④",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "토낭백 규격(가×세×높이)", "적용": "80×40×20", "단위": "㎝" },
{ "구분": "토낭백 규격(가능)", "적용": "60×40×20", "단위": "㎝" },
{ "구분": "식생포트 1개당 본수", "적용": 3, "단위": "본" },
{ "구분": "식생포트 보통인부", "적용": 0.033, "단위": "인/본" }
],
"주": []
},
{
"열쇠": "13-15-2 횡목 직경",
"이름": "목책 설치 횡목 직경",
"기준": "",
"출처": "산림품셈 13-15-2 주③",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "횡목 직경 제한", "적용": [20, 30], "단위": "㎝", "적용원문": "20 30cm" }
],
"주": []
},
{
"열쇠": "13-16-1 매트 주 계산용 수",
"이름": "필터매트 주 속 계산용 수",
"기준": "",
"출처": "산림품셈 13-16-1 주⑤⑦",
"조건": { "구분": "고르기" },
"값칸": { "적용": "줄 따름", "적용원문": "글", "단위": "글" },
"줄": [
{ "구분": "수중 부설 수심(이하 기준)", "적용": 10, "단위": "m" },
{ "구분": "공구손료 및 경장비(봉합기) 기계경비(인력품의)", "적용": 4, "단위": "%" }
],
"주": []
}
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -46,7 +46,7 @@
"값칸": { "적용": "구분 따름", "적용원문": "글", "비고": "글" },
"줄": [
{ "구분": "K", "적용": 0.9 },
{ "구분": "f", "적용원문": "1/1.30" },
{ "구분": "f", "적용": "1/1.30", "적용원문": "1/1.30" },
{ "구분": "E", "적용": [0.45, 0.55], "적용원문": "0.550.45" },
{ "구분": "㎝(sec)", "적용": 20, "적용원문": "20(135°)" }
],
@@ -90,7 +90,7 @@
"값칸": { "적용": "구분 따름", "적용원문": "글", "비고": "글" },
"줄": [
{ "구분": "K", "적용": 0.55 },
{ "구분": "f", "적용원문": "1/1.40" },
{ "구분": "f", "적용": "1/1.40", "적용원문": "1/1.40" },
{ "구분": "E", "적용": 0.35 },
{ "구분": "㎝(sec)", "적용": 20, "적용원문": "20(135°)" }
],
@@ -143,7 +143,7 @@
"값칸": { "적용": "구분 따름", "적용원문": "글", "비고": "글" },
"줄": [
{ "구분": "K", "적용": 0.55 },
{ "구분": "f", "적용원문": "1/1.625" },
{ "구분": "f", "적용": "1/1.625", "적용원문": "1/1.625" },
{ "구분": "E", "적용": 0.35 },
{ "구분": "㎝(sec)", "적용": 20, "적용원문": "20(135°)" }
],
@@ -386,11 +386,12 @@
{ "구분": "거리(L)", "단위": "km", "적용": 0.1 },
{ "구분": "운반속도(V)", "단위": "km/hr", "적용": 2.5 },
{ "구분": "적재적하시간(t)", "단위": "min", "적용": 4.0 },
{ "구분": "일일실작업시간(T)", "단위": "분", "적용원문": "480분-30분" },
{ "구분": "일일실작업시간(T)", "단위": "분", "적용": "480분-30분", "적용원문": "480분-30분" },
{ "구분": "1회 운반량(q)", "단위": "", "적용": 25 }
],
"주": [
"표 안 비고(여섯 줄 병합): N=(V×T)/(120×L+V.t)= 회/일 Q = N×q = /일"
"표 안 비고(여섯 줄 병합): N=(V×T)/(120×L+V.t)= 회/일 Q = N×q = /일",
"표 안 빈 줄: 1일 운반횟수(N) · 회 · 적용 칸 비어 있음"
]
},
{
@@ -473,21 +474,6 @@
"집수정, 맨홀 등 배수구조물의 터파기에 적용한다."
]
},
{
"열쇠": "9-13 관보호공 보통인력 가산",
"이름": "구조물터파기 관보호공·관부설 보통인력 의무 가산",
"그룹": "계수",
"기준": "",
"출처": "산림품셈 9-13",
"조건": { "구분": "고르기" },
"값칸": { "가산율": "%" },
"줄": [
{ "구분": "관보호공 설치 · 관부설 공사", "가산율": 30 }
],
"주": [
"※ 관보호공의 설치, 관부설 공사의 경우 돌 구름, 토사붕괴를 관리하기 위하여 보통인력 30%를 의무화하여 가산한다."
]
},
{
"열쇠": "9-13-2 육상토사(12m)",
"이름": "구조물터파기 육상토사(12m)",
@@ -801,7 +787,7 @@
"값칸": { "적용": "구분 따름", "적용원문": "글", "비고": "글" },
"줄": [
{ "구분": "K(버킷계수)", "적용": 0.9 },
{ "구분": "f(토량환산계수)", "적용원문": "1/1.30" },
{ "구분": "f(토량환산계수)", "적용": "1/1.30", "적용원문": "1/1.30" },
{ "구분": "E(작업효율)", "적용": 0.7 },
{ "구분": "㎝(1회 사이클시간)", "적용": 20, "적용원문": "20(135°) sec" }
],
@@ -826,10 +812,10 @@
{ "구분": "T(표토두께)", "단위": "m", "적용": 0.2 },
{ "구분": "L(운반거리)", "단위": "m", "적용": 20 },
{ "구분": "E(작업효율)", "적용": 0.4 },
{ "구분": "q(삽날의 용량)", "적용원문": "q0×e(㎥)" },
{ "구분": "q(삽날의 용량)", "적용": "q0×e(㎥)", "적용원문": "q0×e(㎥)" },
{ "구분": "q0(거리를 고려하지 않은 삽날의 용량)", "단위": "㎥", "적용": 3.2 },
{ "구분": "e(운반거리계수)", "적용": 0.96 },
{ "구분": "f(토량환산계수)", "적용원문": "1/1.3" },
{ "구분": "f(토량환산계수)", "적용": "1/1.3", "적용원문": "1/1.3" },
{ "구분": "V1(전진속도)", "단위": "m/분", "적용": 40, "적용원문": "40m/분(1단)" },
{ "구분": "V2(후진속도)", "단위": "m/분", "적용": 46, "적용원문": "46m/분(1단)" },
{ "구분": "t(기어변속시간)", "단위": "분", "적용": 0.25 }
@@ -852,10 +838,10 @@
"값칸": { "적용": "줄 따름", "적용원문": "글" },
"줄": [
{ "구분": "L", "단위": "m", "적용": 20 },
{ "구분": "E", "적용원문": "(0.55-0.1)" },
{ "구분": "E", "적용": "(0.55-0.1)", "적용원문": "(0.55-0.1)" },
{ "구분": "q0", "단위": "m", "적용": 3.2 },
{ "구분": "e", "적용": 0.96 },
{ "구분": "f", "적용원문": "1/1.3" },
{ "구분": "f", "적용": "1/1.3", "적용원문": "1/1.3" },
{ "구분": "V1", "단위": "m/분", "적용": 75, "적용원문": "75m/분(3단)" },
{ "구분": "V2", "단위": "m/분", "적용": 98, "적용원문": "98m/분(3단)" },
{ "구분": "t", "단위": "분", "적용": 0.25 }
@@ -877,7 +863,7 @@
"값칸": { "적용": "구분 따름", "적용원문": "글", "비고": "글" },
"줄": [
{ "적용장비": "굴착기(무한궤도, 0.7㎥)", "구분": "K", "적용": 0.9 },
{ "적용장비": "굴착기(무한궤도, 0.7㎥)", "구분": "f", "적용원문": "1/1.3" },
{ "적용장비": "굴착기(무한궤도, 0.7㎥)", "구분": "f", "적용": "1/1.3", "적용원문": "1/1.3" },
{ "적용장비": "굴착기(무한궤도, 0.7㎥)", "구분": "E", "적용": 0.7 },
{ "적용장비": "굴착기(무한궤도, 0.7㎥)", "구분": "㎝(sec)", "적용": 22, "적용원문": "22(180°)" }
],
@@ -1036,7 +1022,7 @@
"값칸": { "적용": "구분 따름", "적용원문": "글", "비고": "글" },
"줄": [
{ "구분": "K(버킷계수)", "적용": 0.9 },
{ "구분": "f(토량환산계수)", "적용원문": "1/1.25" },
{ "구분": "f(토량환산계수)", "적용": "1/1.25", "적용원문": "1/1.25" },
{ "구분": "E(작업효율)", "적용": 0.75 },
{ "구분": "Cm(1회 사이클시간)", "적용": 18, "적용원문": "18(90°)sec" }
],
File diff suppressed because it is too large Load Diff