feat(801-5): M01 로직 단위 글 건설품셈 원문 꼴 — 시간당 ㎥ · ㎡ → hr · 초 → sec · mm · cm · kg → ㎜ · ㎝ · ㎏ · TON · t → ton · km/hr → ㎞/hr

- 대응표 master_unit_text.RULES(규칙마다 원문 근거 절) · 빌더 build_단위표기_801_5(--check · --list · 셈 지문 전후 같을 때만 씀)
- M01 로직 53 개 · 칸 79 개 글만 바꿈(변수 입력 · 중간 단위 · 결과단위) · 계수 · 소요량 표 값칸 · 호표 줄 단위 · 원문이 두 꼴을 다 쓰는 단위(㎞ · km · 분 · min)는 안 건드림
- M02 사본 새로 씀 도구 M02_Copy_Units(M02_Copy_Symbols 의 fill 만 바꿔 끼움) — 사본 16 문서 28 칸 · 금액 전후 같음
- 검토 목록 docs/raw/요구_1104/_목록_801-5_단위표기.xlsx
- 옛 시험 기대 고침: test_796_3 굴착기 cm 단위 초 → sec(원문 표 머리 「싸이클시간(Sec)」)
- 새 test_801_5_units 6

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-07 18:00:30 +09:00
co-authored by Claude Sonnet 5.5
parent 4baf69803e
commit d7e6fe5cf8
29 changed files with 522 additions and 98 deletions
@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
"""M01 로직 단위 글을 건설품셈 원문 꼴로 (PLAN 801-5 · 요구 663-2) — 글만 바꿈 · 셈 지문 그대로.
돌리기: ./venv/Scripts/python.exe resources/master_data/scripts/build_단위표기_801_5.py [--check | --list 파일.xlsx]
- 대상 = M01 로직 줄의 입력 · 중간 변수 `단위` · `결과단위` — 규칙 · 근거 절 = `master_unit_text.RULES`.
- 계수 · 소요량 표 값칸 · 호표 줄 단위 · 사용자가 이미 원문 꼴로 쓴 칸은 안 건드림(이미 같으면 그대로 — 두 번 돌려도 같음).
- 쓰기 전 지문 대조 = 줄마다 엔진 셈 · 끝수 지문이 전후 같을 때만 씀(다르면 멈춤).
- `--check` = 쓰지 않고 쓸 것이 남았는지만(남았으면 종료 코드 1) · `--list` = 검토 목록 xlsx 만 씀(마스터 안 씀).
"""
from __future__ import annotations
import copy
import hashlib
import json
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE.parents[2]))
import master_auto as ma # noqa: E402
import master_cut as mcut # noqa: E402
import master_formula as mf # noqa: E402
import master_unit_text as ut # noqa: E402
from M01_MasterData import M01_MasterData_Store as st # noqa: E402
def plan(files: dict[str, dict]) -> tuple[list[dict], list[dict], dict[str, dict]]:
"""(저장 묶음, 목록 줄들, 새 files) — 읽기 전용."""
batch, rows, new_files = [], [], {}
for name, data in files.items():
if data.get("그룹") != "로직":
new_files[name] = data
continue
changes, new_data = [], copy.deepcopy(data)
for row in new_data.get("줄", []):
hit = False
for kind in ("입력", "중간"):
for spec in row.get(kind) or []:
now = ut.canon(spec.get("단위"))
if now != (spec.get("단위") or ""):
rows.append(_item(row, kind, spec["이름"], spec["단위"], now))
spec["단위"], hit = now, True
if row.get("결과단위"):
now = ut.canon(row["결과단위"])
if now != row["결과단위"]:
rows.append(_item(row, "결과단위", "", row["결과단위"], now))
row["결과단위"], hit = now, True
if hit:
changes.append({"op": "edit", "key": row["키"], "row": row})
new_files[name] = new_data
if changes:
batch.append({"file": name, "version": st.read(name)[1], "changes": changes})
return batch, rows, new_files
def _item(row: dict, kind: str, var: str, before: str, after: str) -> dict:
return {
"로직": row["키"],
"이름": row.get("이름", ""),
"칸": kind,
"변수": var,
"지금": before,
"원문 꼴": after,
"규칙": ut.rule_of(before),
}
def fingerprint(whole: mf.Master, row: dict) -> str:
"""줄 하나의 엔진 셈 · 끝수 지문 — 멈춤도 지문."""
try:
key = str(row["키"])
raw = mf.run(
whole,
key,
{
**ma.values(whole, row),
**{k: v for k, v in ma.defaults(whole, row).items() if v is not None},
},
)
text = json.dumps(raw, default=str, sort_keys=True, ensure_ascii=False)
text += json.dumps(
mcut.engine(whole, key, raw), default=str, sort_keys=True, ensure_ascii=False
)
except Exception as e: # noqa: BLE001
text = f"ERR {type(e).__name__} {e}"
return hashlib.sha256(text.encode()).hexdigest()[:16]
def differing(old: dict[str, dict], new: dict[str, dict]) -> list[str]:
"""지문이 바뀐 로직 키들 — 고친 줄만 대조."""
before, after = mf.Master(old), mf.Master(new)
out = []
for name, data in new.items():
if data.get("그룹") != "로직":
continue
was = {r["키"]: r for r in old[name]["줄"]}
for row in data["줄"]:
if row != was[row["키"]] and fingerprint(before, was[row["키"]]) != fingerprint(
after, row
):
out.append(row["키"])
return out
def write_list(rows: list[dict], path: Path) -> None:
import openpyxl
book = openpyxl.Workbook()
sheet = book.active
sheet.title = "바뀜"
cols = ["로직", "이름", "칸", "변수", "지금", "원문 꼴", "규칙"]
sheet.append(cols)
for r in rows:
sheet.append([r[c] for c in cols])
rule = book.create_sheet("대응표")
rule.append(["규칙", "바꿀 글", "근거 절(건설공사 표준품셈 본문 아래)", "바뀐 칸 수"])
for name, _, to, _, files in ut.RULES:
rule.append([name, to, " · ".join(files), sum(name in r["규칙"] for r in rows)])
path.parent.mkdir(parents=True, exist_ok=True)
book.save(path)
def main() -> None:
files, _ = st.loaded()
batch, rows, new_files = plan(files)
print(f"쓸 것 — 로직 {len({r['로직'] for r in rows})} · 칸 {len(rows)}")
if "--list" in sys.argv:
write_list(rows, Path(sys.argv[sys.argv.index("--list") + 1]))
return
if "--check" in sys.argv:
raise SystemExit(1 if batch else 0)
if batch:
bad = differing(files, new_files)
if bad:
raise SystemExit(f"셈 지문이 달라지는 로직 {len(bad)} — 멈춤: {bad[:10]}")
print(st.save(batch))
if __name__ == "__main__":
main()
@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
"""M01 로직 단위 글 → 건설품셈 원문 꼴(PLAN 801-5 · 요구 663-2) — 글만 바꿈 · 셈 · 환산 안 바꿈.
`canon(단위 글)` = 아래 `RULES` 를 차례로 적용(이미 원문 꼴이면 그대로 · 두 번 돌려도 같음).
`RULES` 한 줄 = (이름, 지금 글 정규식, 바꿀 글, 원문 글, 근거 절들) — 근거 절 = `EVIDENCE_ROOT` 아래 파일 ·
그 파일 안에 원문 글이 실제로 있어야 함(시험 `test_801_5_units`). 원문이 두 꼴을 다 쓰는 단위(㎞ · km · 분 · min)는 안 건드림.
단위 칸 중 원문 표를 그대로 옮긴 계수 · 소요량 표 값칸 · 호표 줄 단위(요소 단위)는 대상 아님.
"""
from __future__ import annotations
import re
from pathlib import Path
EVIDENCE_ROOT = Path("resources/knowledge/original/원가계산/건설공사_표준품셈/본문")
_A = r"(?<![A-Za-z])" # 영문 낱말 한가운데는 안 건드림
_Z = r"(?![A-Za-z])"
# (이름, 지금 글 정규식, 바꿀 글, 원문 글, 근거 절들)
RULES: list[tuple[str, str, str, str, list[str]]] = [
(
"시간당 ㎥ · ㎡ → hr",
r"(?<=[㎥㎡])/시간(?![가-힣])",
"/hr",
"/hr",
[
"01_공통부문/제08장_건설기계/8-03-05_[40]콘크리트기계.md", # ㎥/hr
"02_토목부문/제07장_항만공사/7-02_사석.md", # ㎡/hr
],
),
(
"사이클 시간 초 → sec",
r"(?<![가-힣])초(?![가-힣])",
"sec",
"sec",
[
"01_공통부문/제05장_기초공사/5-02_연약지반처리.md", # cm : 1회 싸이클 타임(sec)
"01_공통부문/제08장_건설기계/8-02-02_리퍼(유압식).md",
],
),
(
"mm → ㎜",
rf"{_A}mm{_Z}",
"㎜",
"㎜",
["04_기계설비부문/제13장_플랜트설비공사/13-01_플랜트_배관.md"],
),
(
"cm → ㎝",
rf"{_A}cm{_Z}",
"㎝",
"㎝",
["01_공통부문/제08장_건설기계/8-03-06_[50]골재생산기계_등.md"],
),
("kg → ㎏", rf"{_A}kg{_Z}", "㎏", "㎏", ["01_공통부문/제01장_적용기준/1-02_설계_및_수량.md"]),
(
"km/hr → ㎞/hr",
rf"{_A}km/hr",
"㎞/hr",
"㎞/hr",
["01_공통부문/제08장_건설기계/8-02-09_롤러.md"],
),
(
"TON · t → ton",
rf"{_A}(?:TON|t){_Z}",
"ton",
"ton",
["01_공통부문/제08장_건설기계/8-02-12_크러셔.md"],
),
]
_COMPILED = [(name, re.compile(pat), to, tok, files) for name, pat, to, tok, files in RULES]
def canon(unit) -> str:
"""원문 꼴 단위 글 — 규칙에 안 걸리면 그대로."""
text = str(unit or "")
for _, pat, to, _, _ in _COMPILED:
text = pat.sub(to, text)
return text
def rule_of(before: str) -> str:
"""바뀐 단위가 걸린 규칙 이름들(검토 목록 · 대응표용)."""
out, text = [], str(before or "")
for name, pat, to, _, _ in _COMPILED:
if pat.search(text):
out.append(name)
text = pat.sub(to, text)
return " · ".join(out)
@@ -217,7 +217,7 @@
{ "이름": "인원", "식": "무게 / 운반량", "단위": "인" },
{ "이름": "환산계수", "식": "만약(경사각도 > 0, 찾기(CC000347, 각도=경사각도).환산계수, 1)" },
{ "이름": "환산거리", "식": "환산계수 * 운반거리", "단위": "km" },
{ "이름": "왕복평균속도", "식": "찾기(CC000345, 도로상태=도로상태).왕복평균속도", "단위": "km/hr" },
{ "이름": "왕복평균속도", "식": "찾기(CC000345, 도로상태=도로상태).왕복평균속도", "단위": "㎞/hr" },
{ "이름": "준비작업시간", "식": "찾기(CC000346).준비작업시간", "단위": "분" },
{ "이름": "작업시간", "식": "만약(실작업시간 > 0, 실작업시간, 찾기(CC000342).실작업시간)", "단위": "분" }
],
@@ -280,7 +280,7 @@
"구분": "건설품셈 공통",
"상세구분": "01장 적용기준",
"이름": "건설폐기물 발생량 — 건설 공통 1-5-4",
"결과단위": "TON",
"결과단위": "ton",
"출처": "건설품셈 공통 1-5-4 2",
"개정": [2011, 2014, 2017, 2020],
"소유": "공용",
@@ -293,7 +293,7 @@
{ "이름": "면적", "설명": "단위면적 산출 면적", "단위": "㎡", "출처": "건설품셈 공통 1-5-4 2" },
{ "이름": "증가율", "설명": "폐콘크리트 수량 증가(%) — 주③ 파일 15 · 20% 이내 · 주④ 세륜 개소당 3% 이내 · 0 = 없음", "단위": "%", "출처": "건설품셈 공통 1-5-4 2 주③ ④" }
],
"중간": [{ "이름": "원단위", "식": "찾기(CC000519, 공사=공사, 구조=구조, 폐기물=폐기물).발생량", "단위": "TON/㎡" }, { "이름": "증가", "식": "만약(폐기물 == '폐콘크리트류', 증가율 / 100, 0)" }],
"중간": [{ "이름": "원단위", "식": "찾기(CC000519, 공사=공사, 구조=구조, 폐기물=폐기물).발생량", "단위": "ton/㎡" }, { "이름": "증가", "식": "만약(폐기물 == '폐콘크리트류', 증가율 / 100, 0)" }],
"결과": { "식": "면적 * 원단위 * (1 + 증가)", "출처": "건설품셈 공통 1-5-4 2" },
"끝수": null,
"변수표": {
@@ -12,13 +12,13 @@
"구분": "건설품셈 건축",
"상세구분": "01장 철골공사",
"이름": "철골 공장가공조립(기본철골공수)",
"결과단위": "원/t",
"결과단위": "원/ton",
"출처": "건설품셈 건축 1-1-1",
"개정": [2008, 2013],
"소유": "공용",
"비고": "공수에 비계 · 보조공 포함(주①) · 제경비에 산재보험료 · 간접노무비 · 일반관리비 · 이윤 없음(주③) · 용접은 1-1-3 · 부자재는 1-1-2(현장 세우기 제외) · 서비스볼트 규격은 설계에 따름 · 해석: 작업난이도(1-1-2)를 공수에 곱함",
"입력": [
{ "이름": "강재총사용량", "단위": "t", "출처": "건설품셈 건축 1-1-1" },
{ "이름": "강재총사용량", "단위": "ton", "출처": "건설품셈 건축 1-1-1" },
{ "이름": "부재", "고르기": ["전용접부재", "H형강부재"], "출처": "건설품셈 건축 1-1-1 비고", "비고": "전용접부재(Built up) · H형강부재(Rolled shape)" },
{ "이름": "작업난이도", "단위": "배", "범위": [0.8, 1.2], "출처": "건설품셈 건축 1-1-2", "비고": "구조공별 — 가공부재 종류 적은 구조 0.8∼0.95 · 표준라멘 1.0 · 종류 많은 구조 1.05∼1.2" },
{ "이름": "공수직종", "고르기": ["1011", "1012"], "출처": "건설품셈 건축 1-1-1", "비고": "원문 「인·일」에 직종 없음 — 설계자가 고름(1011 철골공 · 1012 용접공) · 공장제작 노임을 쓰면 관리자가 바꿈" }
@@ -81,13 +81,13 @@
"구분": "건설품셈 건축",
"상세구분": "01장 철골공사",
"이름": "철골 공장용접(기본용접공수)",
"결과단위": "원/t",
"결과단위": "원/ton",
"출처": "건설품셈 건축 1-1-3",
"소유": "공용",
"비고": "해석: 기본용접공수 = 용접공 · 1-1-4 보정계수(강재총사용량)를 공수에 곱함 · 용접재료는 환산용접길이(m/t) × m당 양 · 제경비에 산재보험료 · 간접노무비 · 일반관리비 · 이윤 없음(주③) · 특수 구조물은 기계설비부문 플랜트용접 참조(주⑤)",
"입력": [
{ "이름": "환산용접길이", "단위": "m/t", "출처": "건설품셈 건축 1-1-3 주④", "비고": "용접길이 × 환산계수(필릿 · V·K·X 판두께별 계수표) — 필릿 각장 6㎜ 환산" },
{ "이름": "강재총사용량", "단위": "t", "출처": "건설품셈 건축 1-1-4" },
{ "이름": "환산용접길이", "단위": "m/ton", "출처": "건설품셈 건축 1-1-3 주④", "비고": "용접길이 × 환산계수(필릿 · V·K·X 판두께별 계수표) — 필릿 각장 6㎜ 환산" },
{ "이름": "강재총사용량", "단위": "ton", "출처": "건설품셈 건축 1-1-4" },
{ "이름": "부재", "고르기": ["전용접부재", "H형강부재"], "출처": "건설품셈 건축 1-1-1 비고", "비고": "전용접부재(Built up) · H형강부재(Rolled shape)" },
{ "이름": "용접방식", "고르기": ["수용접", "반자동용접", "자동용접"], "출처": "건설품셈 건축 1-1-4", "비고": "반자동용접이 표준" }
],
@@ -348,7 +348,7 @@
"개정": [2008, 2018, 2023],
"소유": "공용",
"비고": "본조임 · 조임검사 포함 · 철골설계수량 300ton 이상은 보정계수 a를 곱함(주④)",
"입력": [{ "이름": "볼트본수본t", "단위": "본/t", "출처": "건설품셈 건축 1-2-4" }, { "이름": "강재총사용량", "단위": "t", "출처": "건설품셈 건축 1-2-4 주④" }],
"입력": [{ "이름": "볼트본수본t", "단위": "본/ton", "출처": "건설품셈 건축 1-2-4" }, { "이름": "강재총사용량", "단위": "ton", "출처": "건설품셈 건축 1-2-4 주④" }],
"중간": [
{ "이름": "보정a", "식": "만약(강재총사용량 < 300, 1, 찾기(CC000165, '강재총사용량(t)'=강재총사용량, '1t당 볼트본수(본)'=볼트본수본t).'보정계수 a')", "출처": "건설품셈 건축 1-2-4 주④" },
{ "이름": "철골공", "식": "찾기(QC001195, '1t당 볼트본수(본/t)'=볼트본수본t).철골공 * 보정a" },
@@ -1740,7 +1740,7 @@
"개정": [2018],
"소유": "공용",
"비고": "재료량 할증 포함 · 그물망 손율 100% · 보강재 손율 원문 없음 — 재료량 그대로",
"입력": [{ "이름": "결속선량", "단위": "kg/10㎡", "범위": [0.3, 0.4], "출처": "건설품셈 공통 2-8-7 재료량" }],
"입력": [{ "이름": "결속선량", "단위": "㎏/10㎡", "범위": [0.3, 0.4], "출처": "건설품셈 공통 2-8-7 재료량" }],
"중간": [{ "이름": "비계공", "식": "찾기(QC000084, 구분='비계공').수량 / 10" }, { "이름": "보통인부", "식": "찾기(QC000084, 구분='보통인부').수량 / 10" }],
"호표": [
{ "종류": "인력", "요소": "LB000006", "이름": "비계공", "단위": "인", "수량": "비계공", "비목": "노무비" },
@@ -1609,9 +1609,9 @@
"이름": "t1",
"식": "만약(타설깊이 <= 25, 찾기(QC000348, L='25이하').t_1, 만약(타설깊이 <= 30, 찾기(QC000348, L='30이하').t_1, 만약(타설깊이 <= 35, 찾기(QC000348, L='35이하').t_1, 만약(타설깊이 <= 40, 찾기(QC000348, L='40이하').t_1, 만약(타설깊이 <= 45, 찾기(QC000348, L='45이하').t_1, 만약(타설깊이 <= 50, 찾기(QC000348, L='50이하').t_1, 만약(타설깊이 <= 55, 찾기(QC000348, L='55이하').t_1, 0)))))))",
"출처": "건설품셈 공통 5-2-3 준비 및 이동시간",
"단위": "초"
"단위": "sec"
},
{ "이름": "cm", "식": "t1 + 타설깊이 / 찾기(QC000349, N치=N치).V_1 + 타설깊이 / 찾기(QC000349, N치=N치).V_2", "출처": "건설품셈 공통 5-2-3 cm", "단위": "초" },
{ "이름": "cm", "식": "t1 + 타설깊이 / 찾기(QC000349, N치=N치).V_1 + 타설깊이 / 찾기(QC000349, N치=N치).V_2", "출처": "건설품셈 공통 5-2-3 cm", "단위": "sec" },
{ "이름": "Q", "식": "3600 * 타설깊이 * 찾기(QC000347, 구분=현장).효율 / cm", "출처": "건설품셈 공통 5-2-3 Q", "단위": "m/hr" },
{ "이름": "T", "식": "1 / Q" },
{ "이름": "특별인부", "식": "찾기(QC000344, 구분='특별인부').수량 * T / 8" },
@@ -168,7 +168,7 @@
"구분": "건설품셈 토목",
"상세구분": "07장 항만공사",
"이름": "수중고르기 잠수부 1조 시간당 고르기 면적",
"결과단위": "㎡/시간",
"결과단위": "㎡/hr",
"출처": "건설품셈 토목 7-2-5",
"개정": [2021],
"소유": "공용",
@@ -323,7 +323,7 @@
"입력": [
{
"이름": "관경",
"단위": "mm",
"단위": "㎜",
"고르기": ["250이하", "300", "350", "400", "510", "560", "610", "630", "660", "685", "710", "760", "840", "860"],
"출처": "건설품셈 토목 7-4-1"
},
@@ -376,7 +376,7 @@
"소유": "공용",
"비고": "크레인 규격 띄우개 관경 430∼1,400 10톤 · 1,500 이상 15톤(주③ 장비규격 표) · 같은 톤 크롤러·타이어 크레인 가능(주④) · 철거는 본 품 30%까지 감(주①) — 감률 설계자 입력 · 소운반 포함 · 체결부 절단 별도",
"입력": [
{ "이름": "관경", "단위": "mm", "고르기": [430, 500, 600, 700, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600], "출처": "건설품셈 토목 7-4-2" },
{ "이름": "관경", "단위": "㎜", "고르기": [430, 500, 600, 700, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600], "출처": "건설품셈 토목 7-4-2" },
{ "이름": "작업", "고르기": ["설치", "철거"], "출처": "건설품셈 토목 7-4-2 주①" },
{ "이름": "철거감률", "단위": "%", "범위": [0, 30], "출처": "건설품셈 토목 7-4-2 주①" },
{
@@ -419,7 +419,7 @@
"소유": "공용",
"비고": "크레인 규격 관경 200∼710 10톤 · 760 이상 15톤(주④ 장비규격 표) · 해상관 1set = 배송관 1본+고무슬리브 1본+띄우개 1본 · 침설관 1set = 배송관 2본+고무슬리브 1본 · 배송관 예인·침설 제외(주①)",
"입력": [
{ "이름": "배송관관경", "단위": "mm", "고르기": [200, 250, 300, 350, 400, 510, 560, 610, 630, 660, 685, 710, 760, 840, 860], "출처": "건설품셈 토목 7-4-3" },
{ "이름": "배송관관경", "단위": "㎜", "고르기": [200, 250, 300, 350, 400, 510, 560, 610, 630, 660, 685, 710, 760, 840, 860], "출처": "건설품셈 토목 7-4-3" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -1308,13 +1308,13 @@
{ "이름": "협소현장", "설명": "주택가 상하수도관로부설 등 협소현장(주⑦)", "고르기": ["해당 없음", "상하수도관로부설 등 협소현장"], "출처": "건설품셈 공통 8-2-3 2 주⑦" },
{ "이름": "f", "설명": "체적환산계수 — 토질 · 상태 변화율(건설 공통 1-2-3)", "출처": "건설품셈 공통 8-1-4" },
{ "이름": "E입력", "설명": "작업효율을 직접 넣을 때 — 0 이면 원문 표 값", "범위": [0, 1], "출처": "건설품셈 공통 8-2-3" },
{ "이름": "싸이클입력", "설명": "1회 싸이클시간을 직접 넣을 때 — 0 이면 표", "단위": "초", "범위": [0, 30], "출처": "건설품셈 공통 8-2-3 3" }
{ "이름": "싸이클입력", "설명": "1회 싸이클시간을 직접 넣을 때 — 0 이면 표", "단위": "sec", "범위": [0, 30], "출처": "건설품셈 공통 8-2-3 3" }
],
"중간": [
{ "이름": "K", "식": "찾기(CC000042, 현장조건=버킷조건).K" },
{ "이름": "보정", "식": "만약(E보정 == '해당 없음', 0, 찾기(CC000046, 항목=E보정).보정값)" },
{ "이름": "E", "식": "만약(E입력 > 0, E입력, 만약(협소현장 == '해당 없음', 찾기(CC000043, 현장조건=현장조건, 등급=등급, 토질명=토질명).E, 찾기(CC000044, 등급=등급, 토질명=토질명).E) - 보정)" },
{ "이름": "cm", "식": "만약(싸이클입력 > 0, 싸이클입력, 찾기(CC000045, 규격=규격구분, 각도=선회각도).시간)", "단위": "초" }
{ "이름": "cm", "식": "만약(싸이클입력 > 0, 싸이클입력, 찾기(CC000045, 규격=규격구분, 각도=선회각도).시간)", "단위": "sec" }
],
"결과": { "식": "3600 * 버킷용량 * K * f * E / cm", "출처": "건설품셈 공통 8-2-3" },
"끝수": { "대상": "결과", "자리": 3, "방법": "반올림", "출처": "건설품셈 공통 8-1-4 주①" },
@@ -1385,7 +1385,7 @@
{ "이름": "협소현장", "설명": "주택가 상하수도관로부설 등 협소현장(주⑦)", "고르기": ["해당 없음", "상하수도관로부설 등 협소현장"], "출처": "건설품셈 공통 8-2-3 2 주⑦" },
{ "이름": "f", "설명": "체적환산계수 — 토질 · 상태 변화율(건설 공통 1-2-3)", "출처": "건설품셈 공통 8-1-4" },
{ "이름": "E입력", "설명": "작업효율을 직접 넣을 때 — 0 이면 원문 표 값", "범위": [0, 1], "출처": "건설품셈 공통 8-2-3" },
{ "이름": "싸이클입력", "설명": "1회 싸이클시간을 직접 넣을 때 — 0 이면 표", "단위": "초", "범위": [0, 30], "출처": "건설품셈 공통 8-2-3 3" },
{ "이름": "싸이클입력", "설명": "1회 싸이클시간을 직접 넣을 때 — 0 이면 표", "단위": "sec", "범위": [0, 30], "출처": "건설품셈 공통 8-2-3 3" },
{
"이름": "기계",
"설명": "굴착기(무한궤도) 규격",
@@ -1528,12 +1528,12 @@
{ "이름": "E입력", "설명": "작업효율을 직접 넣을 때 — 0 이면 원문 표 값", "범위": [0, 1], "출처": "건설품셈 공통 8-2-5" }
],
"중간": [
{ "이름": "t1", "식": "찾기(CC000047, 기종=기종, 작업방법=작업방법, 현장조건=적재조건).t1", "단위": "초" },
{ "이름": "t1", "식": "찾기(CC000047, 기종=기종, 작업방법=작업방법, 현장조건=적재조건).t1", "단위": "sec" },
{ "이름": "K", "식": "만약(K표 == '산적상태 적재', 찾기(CC000048, 현장조건=K조건).계수, 찾기(CC000049, 현장조건=K조건).계수)" },
{ "이름": "m", "식": "찾기(CC000051, 기종=기종).m", "단위": "초/m" },
{ "이름": "m", "식": "찾기(CC000051, 기종=기종).m", "단위": "sec/m" },
{ "이름": "l", "식": "만약(주행거리 > 0, 주행거리, 찾기(CC000052, 항목='편도주행거리(표준)').값)", "단위": "m" },
{ "이름": "t2", "식": "찾기(CC000052, 항목='기본시간(t2, 기어변화 등)').값", "단위": "초" },
{ "이름": "cm", "식": "m * l + t1 + t2", "단위": "초" },
{ "이름": "t2", "식": "찾기(CC000052, 항목='기본시간(t2, 기어변화 등)').값", "단위": "sec" },
{ "이름": "cm", "식": "m * l + t1 + t2", "단위": "sec" },
{ "이름": "보정", "식": "만약(E보정 == '해당 없음', 0, 찾기(CC000053, 항목=E보정).보정값)" },
{ "이름": "E", "식": "만약(E입력 > 0, E입력, 찾기(CC000050, 현장조건=현장조건, 등급=등급, 토질명=토질명).E - 보정)" }
],
@@ -1907,7 +1907,7 @@
},
"입력": [
{ "이름": "적재용량", "설명": "덤프트럭의 적재용량(T)", "단위": "ton", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "단위중량", "설명": "자연상태 토석의 단위중량(γt · 습윤밀도)", "단위": "t/㎥", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "단위중량", "설명": "자연상태 토석의 단위중량(γt · 습윤밀도)", "단위": "ton/㎥", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "체적변화율", "설명": "체적환산계수에서의 체적변화율(L = 흐트러진/자연)", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "f", "설명": "체적환산계수", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "운반거리", "설명": "운반거리(편도)", "단위": "㎞", "출처": "건설품셈 공통 8-2-8 2" },
@@ -1943,7 +1943,7 @@
{ "이름": "덮개", "설명": "적재함 덮개 설치 · 해체(t5)", "고르기": ["해당 없음", "인력에 의한 경우", "자동덮개시설의 경우"], "출처": "건설품셈 공통 8-2-8 6" },
{ "이름": "세륜", "설명": "세륜기 통과(t6)", "고르기": ["안 함", "함"], "출처": "건설품셈 공통 8-2-8 7" },
{ "이름": "적재방법", "설명": "적재시간(t1) 산출 갈래", "고르기": ["적재기계", "인력", "직접 입력"], "출처": "건설품셈 공통 8-2-8 1 · 8 · 9" },
{ "이름": "적재싸이클", "설명": "적재기계의 1회 싸이클시간(cms)", "단위": "초", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "적재싸이클", "설명": "적재기계의 1회 싸이클시간(cms)", "단위": "sec", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "적재버킷", "설명": "적재기계의 버킷용량(q)", "단위": "㎥", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "버킷계수", "설명": "적재기계의 버킷계수(k)", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "적재효율", "설명": "적재기계의 작업효율(Es)", "출처": "건설품셈 공통 8-2-8 8" },
@@ -2032,7 +2032,7 @@
},
"입력": [
{ "이름": "적재용량", "설명": "덤프트럭의 적재용량(T)", "단위": "ton", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "단위중량", "설명": "자연상태 토석의 단위중량(γt · 습윤밀도)", "단위": "t/㎥", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "단위중량", "설명": "자연상태 토석의 단위중량(γt · 습윤밀도)", "단위": "ton/㎥", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "체적변화율", "설명": "체적환산계수에서의 체적변화율(L = 흐트러진/자연)", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "f", "설명": "체적환산계수", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "운반거리", "설명": "운반거리(편도)", "단위": "㎞", "출처": "건설품셈 공통 8-2-8 2" },
@@ -2068,7 +2068,7 @@
{ "이름": "덮개", "설명": "적재함 덮개 설치 · 해체(t5)", "고르기": ["해당 없음", "인력에 의한 경우", "자동덮개시설의 경우"], "출처": "건설품셈 공통 8-2-8 6" },
{ "이름": "세륜", "설명": "세륜기 통과(t6)", "고르기": ["안 함", "함"], "출처": "건설품셈 공통 8-2-8 7" },
{ "이름": "적재방법", "설명": "적재시간(t1) 산출 갈래", "고르기": ["적재기계", "인력", "직접 입력"], "출처": "건설품셈 공통 8-2-8 1 · 8 · 9" },
{ "이름": "적재싸이클", "설명": "적재기계의 1회 싸이클시간(cms)", "단위": "초", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "적재싸이클", "설명": "적재기계의 1회 싸이클시간(cms)", "단위": "sec", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "적재버킷", "설명": "적재기계의 버킷용량(q)", "단위": "㎥", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "버킷계수", "설명": "적재기계의 버킷계수(k)", "출처": "건설품셈 공통 8-2-8 8" },
{ "이름": "적재효율", "설명": "적재기계의 작업효율(Es)", "출처": "건설품셈 공통 8-2-8 8" },
@@ -3431,7 +3431,7 @@
"중간": [
{ "이름": "f", "식": "만약(f입력 > 0, f입력, 찾기(CC000474, 분류=f분류, 상태=f상태, N값=fN값).f)" },
{ "이름": "k", "식": "만약(k입력 > 0, k입력, 찾기(CC000475, 분류=k분류, 상태=k상태, N값=kN값, 버킷용량=버킷용량).k)" },
{ "이름": "cm", "식": "찾기(CC000476, 버킷용량=버킷용량).싸이클시간 + (평균수심 - 찾기(CC000481, 항목='기준 수심').값) * 찾기(CC000481, 항목='수심 1m 증감당 싸이클시간 증감').값", "단위": "초" },
{ "이름": "cm", "식": "찾기(CC000476, 버킷용량=버킷용량).싸이클시간 + (평균수심 - 찾기(CC000481, 항목='기준 수심').값) * 찾기(CC000481, 항목='수심 1m 증감당 싸이클시간 증감').값", "단위": "sec" },
{ "이름": "E", "식": "찾기(CC000477, 구분=E1).E * 찾기(CC000479, 구분=E2).E" }
],
"결과": { "식": "3600 * 버킷용량 * k * f * E / cm", "출처": "건설품셈 공통 8-2-30" },
@@ -744,7 +744,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -805,7 +805,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -866,7 +866,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -927,7 +927,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-1" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -989,7 +989,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-2" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350, 400, 450, 500], "출처": "건설품셈 토목 8-4-2" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -1051,7 +1051,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350], "출처": "건설품셈 토목 8-4-2" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350], "출처": "건설품셈 토목 8-4-2" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -1122,7 +1122,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300, 350], "출처": "건설품셈 토목 8-4-2" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300, 350], "출처": "건설품셈 토목 8-4-2" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -1193,7 +1193,7 @@
"소유": "공용",
"비고": "해머식 착정공법 · 고성능 착정기(엔진 335.70㎾) · 굴착심도 200m 이하(8-4-2 주①) · 해석: 윙비트·에어해머·버튼비트는 원문 한 칸(병합) — 모든 규격에 같은 값 · 착정기 조종원 직종 설계자 고름(원문 운전사 구분에 없음) · 공시에 없는 재료 = 재료_자체",
"입력": [
{ "이름": "규격", "단위": "mm", "고르기": [100, 150, 200, 250, 300], "출처": "건설품셈 토목 8-4-2" },
{ "이름": "규격", "단위": "㎜", "고르기": [100, 150, 200, 250, 300], "출처": "건설품셈 토목 8-4-2" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -181,7 +181,7 @@
"구분": "건설품셈 건축",
"상세구분": "10장 창호 및 유리공사",
"이름": "커튼월 프레임 설치(스틱월)",
"결과단위": "원/kg",
"결과단위": "원/㎏",
"출처": "건설품셈 건축 10-1-8",
"개정": [2014, 2020, 2026],
"소유": "공용",
@@ -770,7 +770,7 @@
{ "이름": "용접공품", "단위": "인", "출처": "건설품셈 기계설비 13-2-2", "비고": "원문 범위 — 예 두께 3㎜ 0.0055∼0.0037" },
{ "이름": "특별인부품", "단위": "인", "출처": "건설품셈 기계설비 13-2-2", "비고": "원문 범위 — 예 두께 3㎜ 0.0027∼0.0019" },
{ "이름": "산소량", "단위": "ℓ", "출처": "건설품셈 기계설비 13-2-2 주④", "비고": "원문 범위 — 예 두께 3㎜ 16.5∼25.1" },
{ "이름": "LPG량", "단위": "kg", "출처": "건설품셈 기계설비 13-2-2 주④", "비고": "원문 범위 — 예 두께 3㎜ 0.016∼0.025" }
{ "이름": "LPG량", "단위": "㎏", "출처": "건설품셈 기계설비 13-2-2 주④", "비고": "원문 범위 — 예 두께 3㎜ 0.016∼0.025" }
],
"중간": [],
"호표": [
@@ -81,7 +81,7 @@
"구분": "산림품셈",
"상세구분": "03장 작업장 관리",
"이름": "임산물 운반로 신설 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 3-4-2 1",
"개정": [2026],
"소유": "공용",
@@ -1078,7 +1078,7 @@
"시험입력": { "토성": "양토", "막갈이깊이": 15 },
"입력": [
{ "이름": "토성", "설명": "흙의 성질", "고르기": ["사토", "양토", "식토"], "출처": "산림품셈 5-26-1" },
{ "이름": "막갈이깊이", "설명": "가는 깊이(표의 값 중)", "단위": "cm", "고르기": [9, 12, 15, 18, 21], "출처": "산림품셈 5-26-1" }
{ "이름": "막갈이깊이", "설명": "가는 깊이(표의 값 중)", "단위": "㎝", "고르기": [9, 12, 15, 18, 21], "출처": "산림품셈 5-26-1" }
],
"중간": [],
"호표": [{ "종류": "인력", "요소": "LB000002", "이름": "보통인부", "단위": "인", "수량": "찾기(QF000139, 토성=토성, '막갈이깊이(cm)'=막갈이깊이).수량", "비목": "노무비" }],
@@ -1100,7 +1100,7 @@
"시험입력": { "토성": "양토", "막갈이깊이": 15 },
"입력": [
{ "이름": "토성", "설명": "흙의 성질", "고르기": ["사토", "양토", "식토"], "출처": "산림품셈 5-26-2" },
{ "이름": "막갈이깊이", "설명": "가는 깊이(표의 값 중)", "단위": "cm", "고르기": [9, 12, 15, 18, 21], "출처": "산림품셈 5-26-2" }
{ "이름": "막갈이깊이", "설명": "가는 깊이(표의 값 중)", "단위": "㎝", "고르기": [9, 12, 15, 18, 21], "출처": "산림품셈 5-26-2" }
],
"중간": [],
"호표": [{ "종류": "인력", "요소": "LB000002", "이름": "보통인부", "단위": "인", "수량": "찾기(QF000140, 토성=토성, '막갈이깊이(cm)'=막갈이깊이).수량", "비목": "노무비" }],
@@ -1197,7 +1197,7 @@
"구분": "산림품셈",
"상세구분": "05장 식재 및 녹화",
"이름": "복사이식 굴착기 시간당 작업량(Q1)",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 5-29 주④",
"개정": [2026],
"소유": "공용",
@@ -10,7 +10,7 @@
"구분": "산림품셈",
"상세구분": "06장 생육보조",
"이름": "비료주기",
"결과단위": "원/100kg",
"결과단위": "원/100㎏",
"출처": "산림품셈 6-1",
"개정": [2026],
"소유": "공용",
@@ -44,7 +44,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "토사깍기(기계 · 굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-3-2",
"개정": [2026],
"소유": "공용",
@@ -55,7 +55,7 @@
{ "이름": "K", "식": "찾기(QF000249, 구분='K').적용" },
{ "이름": "f", "식": "찾기(CF000122, 구분='f').적용" },
{ "이름": "E", "식": "E입력" },
{ "이름": "Cm", "식": "찾기(QF000249, 구분='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000249, 구분='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -156,7 +156,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "암절취 집토(굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-4-2",
"개정": [2026],
"소유": "공용",
@@ -167,7 +167,7 @@
{ "이름": "K", "식": "찾기(QF000251, 구분='K').적용" },
{ "이름": "f", "식": "찾기(QF000251, 구분='f').적용원문" },
{ "이름": "E", "식": "찾기(QF000251, 구분='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000251, 구분='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000251, 구분='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -297,7 +297,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "발파암 집토(굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-5-3",
"개정": [2026],
"소유": "공용",
@@ -308,7 +308,7 @@
{ "이름": "K", "식": "찾기(QF000254, 구분='K').적용" },
{ "이름": "f", "식": "찾기(QF000254, 구분='f').적용원문" },
{ "이름": "E", "식": "찾기(QF000254, 구분='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000254, 구분='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000254, 구분='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -386,7 +386,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "콘크리트 깨기 집토(굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-7-1 주⑥",
"개정": [2026],
"소유": "공용",
@@ -396,7 +396,7 @@
{ "이름": "K", "식": "찾기(QF000257, 구분='K').적용" },
{ "이름": "f", "식": "찾기(QF000257, 구분='f').적용" },
{ "이름": "E", "식": "찾기(QF000257, 구분='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000257, 구분='㎝(초)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000257, 구분='㎝(초)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -823,7 +823,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "측구터파기 토사 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-12-1",
"개정": [2026],
"소유": "공용",
@@ -833,7 +833,7 @@
{ "이름": "K", "식": "찾기(QF000267, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='k').적용" },
{ "이름": "f", "식": "찾기(QF000267, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='f').적용" },
{ "이름": "E", "식": "찾기(QF000267, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000267, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000267, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -2026,7 +2026,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "되메우기 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-14-1",
"개정": [2026],
"소유": "공용",
@@ -2036,7 +2036,7 @@
{ "이름": "K", "식": "찾기(QF000288, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='k').적용" },
{ "이름": "f", "식": "찾기(QF000288, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='f').적용" },
{ "이름": "E", "식": "찾기(QF000288, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000288, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000288, 이름='유압식백호우(무한궤도,0.7㎥)', 항목='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -2078,7 +2078,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "다짐(플레이트콤펙터) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-14-2",
"개정": [2026],
"소유": "공용",
@@ -2119,7 +2119,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "표토제거 답(畓)구간(굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎡/시간",
"결과단위": "㎡/hr",
"출처": "산림품셈 9-15-1",
"개정": [2026],
"소유": "공용",
@@ -2163,7 +2163,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "표토제거 답(畓)외구간(불도저 19ton) 시간당 작업량",
"결과단위": "㎡/시간",
"결과단위": "㎡/hr",
"출처": "산림품셈 9-15-2",
"개정": [2026],
"소유": "공용",
@@ -2222,7 +2222,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "노체포설 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-16-1 주②",
"개정": [2026],
"소유": "공용",
@@ -2232,7 +2232,7 @@
{ "이름": "K", "식": "찾기(CF000097, 구분='K').적용" },
{ "이름": "f", "식": "찾기(CF000097, 구분='f').적용" },
{ "이름": "E", "식": "찾기(CF000097, 구분='E').적용" },
{ "이름": "Cm", "식": "찾기(CF000097, 구분='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(CF000097, 구분='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q0 * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -2268,13 +2268,13 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "노체다짐 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-16-2 주②",
"개정": [2026],
"소유": "공용",
"입력": [],
"중간": [
{ "이름": "V", "식": "찾기(CF000099, 구분='V(다짐속도,km/hr)').적용", "단위": "km/hr" },
{ "이름": "V", "식": "찾기(CF000099, 구분='V(다짐속도,km/hr)').적용", "단위": "㎞/hr" },
{ "이름": "W", "식": "찾기(CF000099, 구분='W(롤러 유효폭,m)').적용", "단위": "m" },
{ "이름": "E", "식": "찾기(CF000099, 구분='E(작업효율)').적용" },
{ "이름": "D", "식": "찾기(CF000099, 구분='D(펴는 흙의 두께,m)').적용", "단위": "m" },
@@ -2339,7 +2339,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "비다짐(정지 · 불도저 19ton) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-17-2",
"개정": [2026],
"소유": "공용",
@@ -2393,7 +2393,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "층따기(굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-18",
"개정": [2026],
"소유": "공용",
@@ -2404,7 +2404,7 @@
{ "이름": "K", "식": "찾기(QF000293, 구분='K').적용" },
{ "이름": "f", "식": "찾기(QF000293, 구분='f').적용원문" },
{ "이름": "E", "식": "찾기(QF000293, 구분='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000293, 구분='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000293, 구분='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -2639,7 +2639,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "섞기(굴착기 0.7㎥) 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-22",
"개정": [2026],
"소유": "공용",
@@ -10,7 +10,7 @@
"구분": "산림품셈",
"상세구분": "10장 자재․장비 운반",
"이름": "골재운반 덤프트럭 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 10-3-1 주",
"개정": [2026],
"소유": "공용",
@@ -671,7 +671,7 @@
"구분": "산림품셈",
"상세구분": "10장 자재․장비 운반",
"이름": "불도저 운반 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 10-11 주②",
"개정": [2026],
"소유": "공용",
@@ -778,19 +778,19 @@
{
"이름": "로더cm",
"식": "찾기(CC000051, 기종='타이어식').m * 찾기(CC000052, 항목='편도주행거리(표준)').값 + 찾기(CC000047, 기종='타이어식', 작업방법='산적상태에서 담을 때', 현장조건='용이한 경우').t1 + 찾기(CC000052, 항목='기본시간(t2, 기어변화 등)').값",
"단위": "초",
"단위": "sec",
"출처": "건설품셈 공통 8-2-5 1"
},
{
"이름": "Cm",
"식": "만약(로더 == 1, 로더cm, 만약(적재기계 == '0201-0070', 찾기(QF000336, 구분='㎝(초)').값, 찾기(CC000045, 규격=규격구분, 각도=180).시간))",
"단위": "초",
"단위": "sec",
"출처": "산림품셈 10-12-1 주⑤ · 건설품셈 공통 8-2-3 3"
},
{
"이름": "Cms",
"식": "만약(로더 == 1, 로더cm, 만약(적재기계 == '0201-0070', 20, 찾기(CC000045, 규격=규격구분, 각도=135).시간))",
"단위": "초",
"단위": "sec",
"출처": "산림품셈 10-12-1 2. 운반 · 건설품셈 공통 8-2-3 3"
},
{ "이름": "Es", "식": "만약(로더 == 1, E0, 0.85)", "출처": "산림품셈 10-12-1 2. 운반" },
@@ -91,7 +91,7 @@
"구분": "산림품셈",
"상세구분": "11장 가설",
"이름": "쇄석·혼합석 부설 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 11-4 주①",
"개정": [2026],
"소유": "공용",
@@ -102,7 +102,7 @@
{ "이름": "k", "식": "찾기(QF000349, 구분='k(버킷계수)').적용" },
{ "이름": "f", "식": "찾기(QF000349, 구분='f(체적환산계수)').적용" },
{ "이름": "E", "식": "찾기(QF000349, 구분='E(작업효율)').적용" },
{ "이름": "Cm", "식": "찾기(QF000349, 구분='㎝(sec, 1회 사이클 시간)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000349, 구분='㎝(sec, 1회 사이클 시간)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * k * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
@@ -176,7 +176,7 @@
"소유": "공용",
"비고": "원문 플레이트콤팩트 1.54ton — 기계 요소는 1.5ton 하나(1730-0015)",
"입력": [
{ "이름": "규격", "단위": "mm" },
{ "이름": "규격", "단위": "㎜" },
{
"이름": "지역",
"고르기": ["전국평균", "전국", "서울", "경기", "강원", "충북", "충남", "전북", "경북", "경남", "부산", "제주", "대구", "인천", "대전", "울산", "세종", "전남광주"],
@@ -1321,7 +1321,7 @@
"구분": "산림품셈",
"상세구분": "13장 구조물",
"이름": "토양개량제 부설 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 13-13-2",
"개정": [2026],
"소유": "공용",
@@ -1332,7 +1332,7 @@
{ "이름": "K", "식": "찾기(QF000465, 이름='굴착기(0.2㎥)', 항목='k').적용" },
{ "이름": "f", "식": "찾기(QF000465, 이름='굴착기(0.2㎥)', 항목='f').적용" },
{ "이름": "E", "식": "찾기(QF000465, 이름='굴착기(0.2㎥)', 항목='E').적용" },
{ "이름": "Cm", "식": "찾기(QF000465, 이름='굴착기(0.2㎥)', 항목='㎝(sec)').적용", "단위": "초" }
{ "이름": "Cm", "식": "찾기(QF000465, 이름='굴착기(0.2㎥)', 항목='㎝(sec)').적용", "단위": "sec" }
],
"결과": { "식": "반올림(3600 * q * K * f * E / Cm, 3)", "출처": "건설품셈 공통 8-1-4 주①" },
"끝수": "소수 3자리 사사오입(건설품셈 공통 8-1-4 주①)",
+2 -2
View File
@@ -37,7 +37,7 @@
{ "이름": "상차", "설명": "채집한 돌을 덤프에 싣는지", "고르기": ["포함", "안 함"] },
{ "이름": "덤프", "설명": "소운반 덤프트럭", "고르기": ["0602-0025", "0602-0045", "0602-0060", "0602-0080"], "출처": "건설품셈 공통 8-2-8" },
{ "이름": "운반거리", "설명": "소운반 편도 거리 — 0 이면 소운반 없음", "단위": "㎞", "출처": "건설품셈 공통 8-2-8" },
{ "이름": "쌓기무게", "설명": "쌓기 1㎡ 돌 무게", "단위": "t/㎡" },
{ "이름": "쌓기무게", "설명": "쌓기 1㎡ 돌 무게", "단위": "ton/㎡" },
{ "이름": "적하조건", "설명": "덤프 적하 작업조건", "고르기": ["불량", "보통", "양호"], "출처": "건설품셈 공통 8-2-8 4" },
{
"이름": "지역",
@@ -51,7 +51,7 @@
{ "이름": "규격구분", "식": "만약(굴착기 == '0201-0020' 또는 굴착기 == '0201-0040', '0.12∼0.4', 만약(굴착기 == '0201-0100', '1.0∼1.2', '0.6∼0.8'))" },
{ "이름": "K", "식": "찾기(CC000042, 현장조건='버킷에 넣기 어렵고 불규칙한 공극이 생기는 것으로서 발파 또는 리퍼작업 등에 의하여 얻어진 암과 파쇄암, 호박돌, 역 등인 경우').K" },
{ "이름": "E", "식": "찾기(CC000043, 현장조건='흐트러진 상태', 등급=등급, 토질명='파쇄암').E" },
{ "이름": "cm", "식": "찾기(CC000045, 규격=규격구분, 각도=선회각도).시간", "단위": "초" },
{ "이름": "cm", "식": "찾기(CC000045, 규격=규격구분, 각도=선회각도).시간", "단위": "sec" },
{
"이름": "Q",
"식": "로직(GC001147, 버킷용량=q, 규격구분=규격구분, 선회각도=선회각도, 버킷조건='버킷에 넣기 어렵고 불규칙한 공극이 생기는 것으로서 발파 또는 리퍼작업 등에 의하여 얻어진 암과 파쇄암, 호박돌, 역 등인 경우', 현장조건='흐트러진 상태', 등급=등급, 토질명='파쇄암', E보정='해당 없음', 협소현장='해당 없음', f=1, E입력=0, 싸이클입력=0)",
+3 -3
View File
@@ -352,7 +352,7 @@
}
},
"사본": {
"판": "5bcfbe99102ef55d",
"판": "7a470ae53b9da0de",
"시점": "2026-11-07T15:23:23",
"로직": [
{
@@ -2211,7 +2211,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "되메우기 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-14-1",
"개정": [
2026
@@ -2702,7 +2702,7 @@
"입력": [
{
"이름": "규격",
"단위": "mm"
"단위": "㎜"
},
{
"이름": "지역",
+3 -3
View File
@@ -940,7 +940,7 @@
}
},
"사본": {
"판": "5bcfbe99102ef55d",
"판": "7a470ae53b9da0de",
"시점": "2026-11-07T15:23:23",
"로직": [
{
@@ -2799,7 +2799,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "되메우기 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-14-1",
"개정": [
2026
@@ -3290,7 +3290,7 @@
"입력": [
{
"이름": "규격",
"단위": "mm"
"단위": "㎜"
},
{
"이름": "지역",
+2 -2
View File
@@ -247,7 +247,7 @@
}
},
"사본": {
"판": "4066584ac7f0910f",
"판": "90e75b6182c18dcb",
"시점": "2026-11-07T15:23:23",
"로직": [
{
@@ -858,7 +858,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "노체포설 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-16-1 주②",
"개정": [
2026
+3 -3
View File
@@ -508,7 +508,7 @@
}
},
"사본": {
"판": "bf62fc43e50cd058",
"판": "69839ebda29c8cc5",
"시점": "2026-11-07T15:23:24",
"로직": [
{
@@ -1622,7 +1622,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "되메우기 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-14-1",
"개정": [
2026
@@ -1955,7 +1955,7 @@
"입력": [
{
"이름": "규격",
"단위": "mm"
"단위": "㎜"
},
{
"이름": "지역",
+3 -3
View File
@@ -1060,7 +1060,7 @@
}
},
"사본": {
"판": "5bcfbe99102ef55d",
"판": "7a470ae53b9da0de",
"시점": "2026-11-07T15:23:24",
"로직": [
{
@@ -2919,7 +2919,7 @@
"구분": "산림품셈",
"상세구분": "09장 토공",
"이름": "되메우기 굴착기 시간당 작업량",
"결과단위": "㎥/시간",
"결과단위": "㎥/hr",
"출처": "산림품셈 9-14-1",
"개정": [
2026
@@ -3410,7 +3410,7 @@
"입력": [
{
"이름": "규격",
"단위": "mm"
"단위": "㎜"
},
{
"이름": "지역",
+1 -1
View File
@@ -163,7 +163,7 @@ def test_표본_기호_단위_원문_같음():
"작업효율",
"체적환산계수",
)
assert (t["cm"]["이름"], t["cm"]["단위"]) == ("1회 싸이클시간", "초")
assert (t["cm"]["이름"], t["cm"]["단위"]) == ("1회 싸이클시간", "sec") # 801-5 원문 표 머리 「싸이클시간(Sec)」 꼴
carry = (BOOK / "제01장_적용기준/1-02_설계_및_수량.md").read_text(encoding="utf-8")
for line in (
+138
View File
@@ -0,0 +1,138 @@
"""801-5 M01 로직 단위 글 = 건설품셈 원문 꼴(요구 663-2) 지킴 — 글만 바꿈 · 금액 그대로.
① 대응표 근거 — 규칙마다 근거 절 파일이 있고 그 안에 원문 글이 실제로 있음(+ 지금 글은 같은 꼴로 안 쓰임)
② 섞임 0 — M01 로직 입력 · 중간 · 결과단위가 원문 꼴로 다 바뀌어 있음(규칙이 더 바꿀 것 없음 · 두 번 돌려도 같음)
③ 금액 같음 — 변수 단위 글을 지워도 엔진 셈 · 끝수 지문이 같음(단위 글은 셈에 안 듦)
④ M02 사본 도구 — 같은 규칙으로 사본 줄 단위만 바뀌고 `판` 다시 셈
"""
from __future__ import annotations
import copy
import importlib
import re
import pytest
from M01_MasterData import M01_MasterData_Store as store
ut = importlib.import_module("master_unit_text")
mf = importlib.import_module("master_formula")
build = importlib.import_module("build_단위표기_801_5")
def _rows():
for data in store.loaded()[0].values():
if data.get("그룹") == "로직":
yield from data["줄"]
def test_대응표_근거_절에_원문_글이_있음():
assert len(ut.RULES) >= 7
for name, _, to, token, files in ut.RULES:
assert files and to == token, name
for rel in files:
path = ut.EVIDENCE_ROOT / rel
assert path.is_file(), (name, rel)
assert token in path.read_text(encoding="utf-8"), (name, rel)
def test_규칙_예():
got = {
u: ut.canon(u)
for u in ("㎥/시간", "㎡/시간", "㎢/시간", "원/시간", "초", "초/m", "mm", "TON/㎡")
}
assert got == {
"㎥/시간": "㎥/hr",
"㎡/시간": "㎡/hr",
"㎢/시간": "㎢/시간", # 원문 9-5-4 가 쓰는 꼴 — 안 건드림
"원/시간": "원/시간",
"초": "sec",
"초/m": "sec/m",
"mm": "㎜",
"TON/㎡": "ton/㎡",
}
for u in got.values():
assert ut.canon(u) == u # 두 번 돌려도 같음
def test_섞임_0_원문_꼴로_다_바뀜():
left = []
for row in _rows():
units = [row.get("결과단위")] + [
s.get("단위") for k in ("입력", "중간") for s in row.get(k) or []
]
left += [(row["키"], u) for u in units if u and ut.canon(u) != u]
assert not left, left[:5]
def test_굴착기_Cm_sec_Q_hr():
row = store.loaded()[1].logic("GF000088") # 토사깍기(굴착기 0.7㎥) 시간당 작업량
assert {s["단위"] for s in row["중간"] if s["이름"] == "Cm"} == {"sec"}
assert row["결과단위"] == "㎥/hr"
_OLD = ( # 원문 꼴 → 옛 글(되돌려 본 꼴) — 두 꼴로 셈이 같음을 대조
(re.compile(r"(?<![가-힣A-Za-z])sec(?![A-Za-z])"), "초"),
(re.compile(r"(?<=[㎥㎡])/hr"), "/시간"),
(re.compile("㎜"), "mm"),
(re.compile("㎝"), "cm"),
(re.compile("㎏"), "kg"),
(re.compile("㎞/hr"), "km/hr"),
)
def _legacy(text: str) -> str:
for pat, old in _OLD:
text = pat.sub(old, text)
return text
def test_금액_같음_옛_글로_되돌려도_셈_지문_같음():
files = store.loaded()[0]
old = copy.deepcopy(files)
for data in old.values():
if data.get("그룹") == "로직":
for row in data["줄"]:
for k in ("입력", "중간"):
for s in row.get(k) or []:
s["단위"] = _legacy(s.get("단위") or "")
row["결과단위"] = _legacy(row.get("결과단위") or "")
now, was = mf.Master(files), mf.Master(old)
keys = [r["키"] for r in _rows()]
hit = {
r["키"]
for r in _rows()
if any(
_legacy(s.get("단위") or "") != (s.get("단위") or "")
for k in ("입력", "중간")
for s in r.get(k) or []
)
}
assert len(hit) >= 40
for key in sorted(hit) + keys[::25]:
assert build.fingerprint(now, now.logic(key)) == build.fingerprint(was, was.logic(key)), key
def test_M02_사본_도구():
cu = importlib.import_module("M02_MasterTemplete.M02_Copy_Units")
old = {
"로직": [
{
"키": "GC000001",
"결과단위": "㎥/시간",
"입력": [{"이름": "a", "단위": "mm"}],
"중간": [{"이름": "Cm", "단위": "초"}],
}
],
"판": "x",
}
new, done, _ = cu.fill(old, None)
row = new["로직"][0]
assert done == 3 and row["결과단위"] == "㎥/hr" and row["입력"][0]["단위"] == "㎜"
assert row["중간"][0]["단위"] == "sec" and new["판"] != "x"
assert cu.fill(new, None)[1] == 0 # 두 번째 = 바꿀 것 없음
if __name__ == "__main__":
pytest.main([__file__, "-q"])