feat(785-2): Bind B2 · B3 · B4 785-1 꼴 맞춤 · Solve 풂 절 parts · 지킴 시험 test_642_2
- Bind: B2 선택값 줄 = 낱말 같음 고름(「사용횟수」 ≠ 「사용」) · B3 상수 이름 · 덧(90˚) · 단위 맞춤(sec = 초 · km → m) · 경사도 → 경사각도 · B4 식 분자 · 분모 {수|기호} + 대입
- Solve.parts: Formula.works 절 + Clause 후보 {키, 절} → 풂 절(절 표 없는 후보뿐이면 블록 통째)
- 새 test_642_2_bind_solve: 예시 1 · 2 · 3 + 단산46 · 39 입력값 · 출처 꼬리표 · 입력 필요 · 엇갈림 · 지어 넣은 값 0 · 품 같음 · defaults 규칙
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ mf = m01.cm.mf
|
||||
mp = mf.mp
|
||||
mm = mp.mm
|
||||
import master_auto as ma # noqa: E402 — mf 를 불러 scripts 경로가 깔린 뒤
|
||||
import master_unit as mu # noqa: E402
|
||||
|
||||
SKIP = ("지역", "자재지역", "조종원직종")
|
||||
NEG = ("아님", "해당 없음", "없음", "미적용", "사용 안 함")
|
||||
@@ -37,7 +38,10 @@ SYMBOLS = {
|
||||
"L": ("운반거리", "거리"),
|
||||
"n": ("운반회수",),
|
||||
"T": ("실작업시간",),
|
||||
"경사도": ("경사각도",),
|
||||
}
|
||||
_WORDS = re.compile(r"[\s::,/()※*·\[\]{}]+")
|
||||
_SAME_UNIT = {"sec": "초", "s": "초", "min": "분", "hr": "시간", "h": "시간"}
|
||||
_ANGLE = re.compile(r"\(\s*(\d+)\s*[˚°]\s*\)")
|
||||
_MIX = re.compile(r"(?<!\d)(\d{2})-(\d{2,3})-(\d{2,3})(?!\d)")
|
||||
MIX_NAMES = ("굵은골재최대치수", "강도", "슬럼프")
|
||||
@@ -268,8 +272,12 @@ def _b6(got: _Got, line: dict | None, same: list[dict]) -> None:
|
||||
|
||||
def _b2(got: _Got, picks: list[dict], text: str, keys: dict) -> None:
|
||||
"""선택값 줄 · 글에 없는 켜기 칸 = 아님(표 줄을 고르는 찾기 조건 칸은 B5 몫 · 뺌)."""
|
||||
for one in picks or []:
|
||||
_b1(got, {"이름": "", "규격": one.get("글"), "행": one.get("행")}, "B2")
|
||||
for one in picks or []: # 고름 글 = 줄의 낱말 하나와 같음(「사용횟수」 ≠ 「사용」)
|
||||
words = {mm.plain_spec(w) for w in _WORDS.split(str(one.get("글") or "")) if w}
|
||||
for name, spec in got.specs.items():
|
||||
hits = [o for o in spec.get("고르기") or [] if mm.plain_spec(str(o)) in words]
|
||||
if len(hits) == 1:
|
||||
got.put(name, hits[0], "B2", one.get("행"), one.get("글"))
|
||||
flat = mm.plain_spec(text)
|
||||
for name, spec in got.specs.items():
|
||||
opts = spec.get("고르기") or []
|
||||
@@ -281,15 +289,35 @@ def _b2(got: _Got, picks: list[dict], text: str, keys: dict) -> None:
|
||||
got.put(name, neg, "B2", None, f"글에 「{name}」 없음")
|
||||
|
||||
|
||||
def _unit_ok(have: Any, want: Any) -> bool:
|
||||
"""상수 단위 ↔ 입력 단위 — 한쪽이 없음 · 같음(「회/일」 = 회) · 같은 성격(길이 등)."""
|
||||
a, b = (mm.plain_unit(str(u or "").split("/")[0]) for u in (have, want))
|
||||
a, b = _SAME_UNIT.get(a, a), _SAME_UNIT.get(b, b)
|
||||
return not a or not b or a == b or mu.same_kind(a, b)
|
||||
|
||||
|
||||
def _b3(got: _Got, consts: list[dict], master: mf.Master, uses: dict) -> None:
|
||||
for c in consts or []:
|
||||
sym, value, at, text = str(c.get("기호") or ""), c.get("값"), c.get("행"), c.get("글") or ""
|
||||
angle = _ANGLE.search(f"({c.get('덧') or ''}) {c.get('단위') or ''} {text}")
|
||||
if angle:
|
||||
got.put("선회각도", angle.group(1), "B3", at, text)
|
||||
names = [n for n in (c.get("이름"), sym, *SYMBOLS.get(sym, ())) if n and n in got.specs]
|
||||
names = [
|
||||
n
|
||||
for n in (c.get("이름"), sym, *SYMBOLS.get(sym, ()))
|
||||
if n in got.specs and _unit_ok(c.get("단위"), got.specs[n].get("단위"))
|
||||
]
|
||||
if names:
|
||||
got.put(names[0], value, "B3", at, f"{sym} = {plain(_num(value))}")
|
||||
unit = got.specs[names[0]].get("단위")
|
||||
rate = mu.factor(c.get("단위"), unit) if c.get("단위") and unit else None
|
||||
value = _num(value) * rate if rate and _num(value) is not None else value
|
||||
got.put(
|
||||
names[0],
|
||||
value,
|
||||
"B3",
|
||||
at,
|
||||
f"{sym} = {plain(_num(c.get('값')))}{c.get('단위') or ''}",
|
||||
)
|
||||
continue
|
||||
for name, refs in uses.items(): # 표 칸 이름 = 기호 → 그 줄 조건값(K = 0.55 → 버킷조건)
|
||||
if name in got.value or name not in got.specs:
|
||||
|
||||
Reference in New Issue
Block a user