fix(m02-df): 36-2 변환 대조 96.7% — 표 찾기 위 끝 최소 · 값 칸 범위 갈림 · 로직.계 · 조건 찾기 원문번호

- convert(row, ctx={key, file, master}) — sub4 /api/m01/logic/flow 부르는 꼴 · master 는 ctx 것
- {입력} 요소 찾는 값 = 원문번호(「MO:경유:{지역}」 → "경유:"&지역 글 잇는 함수) · 호표 줄 그룹 = 키 앞 두 글자
- 로직(…).계 = 다른 로직 비목 셋 합
- 표 찾기: 여럿이면 범위 위 끝이 가장 작은 줄(옛 find) · 값 칸이 「·아래」 「·위」 로 갈리면 아래 = 위일 때 그 값(Rule · Compute 같음)
- 표 찾기 실패로 넣은 NA() 칸은 칸 계산 오류로 알리지 않음(Eval · Compute)
- 전수 대조는 서버 길 그대로(sub4 조건 찾기 · 표 식 글) · 입력은 옛 엔진처럼 수로 · 까닭 분류
- 시험입력 1,423/1,472(96.7%) · 기본 입력 1,434/1,472(97.4%)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBToTCGk5dqDKeXCEP3vhk
This commit is contained in:
2026-10-02 00:24:22 +09:00
co-authored by Claude Opus 5.5
parent 509e469d56
commit 8193f29ae9
6 changed files with 104 additions and 64 deletions
+15 -9
View File
@@ -139,14 +139,15 @@ class _Flow:
if len(texts) > 1:
raise Unsupported(f"자리 표시가 여러 칸에 낀 요소 「{ref}」")
((at, text),) = texts.items()
holes = list(dict.fromkeys(_HOLE.findall(text)))
if len(holes) == 1:
src, hole = self.hole(holes[0]), holes[0]
else: # 「레미콘 {a}-{b}-{c}」 — 함수 상자가 글을 이음
src = self.func(f"{label} 찾는 말", ("@text", text))
hole = src["name"]
text = "{" + hole + "}"
tpl = text if at is None else json.dumps(plain(ref | {at: text}), ensure_ascii=False)
# 찾는 값 = 원문번호(「EQ:{기계}」 → 기계 · 「MO:경유:{지역}」 → "경유:"&지역)
want = text.partition(":")[2] if at is None and ":" in text else text
if _HOLE.fullmatch(want):
src = self.hole(want[1:-1])
else:
src = self.func(f"{label} 찾는 말", ("@text", want))
if at is not None:
self.notes.append(f"재료 검색어에 입력이 낌 「{text}」 — 조건 찾기(키 같음)로 옮김")
tpl = text if at is None else json.dumps(plain(ref), ensure_ascii=False)
tpl += f"#{field}" if field else ""
rule = {"field": "키", "op": "같음", "from": src}
return ("@port", self.element(group, tpl, unit, f"{label} 자리", rule))
@@ -295,6 +296,9 @@ class _Flow:
group = GROUP_OF.get(base[1][:2], "기계")
node2 = self.priced(group, base[1], "", f"{base[1]} {col}", col)
return self.excel(node2, take, scope)
if base[0] == "logic" and col == "계": # 다른 로직 출력은 비목 셋 — 계 = 그 합
bid = self.logic(base)
return self.excel(("@sum", [{"box": bid, "name": k} for k in COSTS]), take, scope)
if base[0] == "logic":
return take({"box": self.logic(base), "name": col}, f"{base[1]} {col}")
if base[0] == "name" and base[1] == "줄" and f"줄.{col}" in scope:
@@ -356,7 +360,9 @@ def _body(f: _Flow, row: dict) -> None:
lines.setdefault(f"줄.{name}", []).append(part)
continue
unit = str(item.get("단위") or "")
price = f.priced(str(item.get("종류")), item["요소"], unit, f"{name} 단가")
ref = item["요소"] # 그룹 = 키 앞 두 글자(「MO:경유:{지역}」 = 유가전력) · 없으면 줄 종류
group = GROUP_OF.get(ref[:2], str(item.get("종류"))) if isinstance(ref, str) else "재료"
price = f.priced(group, ref, unit, f"{name} 단가")
part = f.func(f"{name} 금액", ("bin", "*", qty, price))
parts[item["비목"]].append(part)
lines.setdefault(f"줄.{name}", []).append(part)