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
+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"])