Files
Aislo/resources/master_data/scripts/master_equation_sign.py
eomsangdonandClaude Opus 5.5 43784a4c09 wip(801-1): 수식 그 자리 고침 · 한 마디 줄 · 로직 부름 기호 · 반올림 · 안 탄 갈래 숨김 — 요구 664 로 멈춤(메인 안 합침)
- 서버: 한 마디 줄(표 찾기 · 요소 · 로직 부름 하나) = 줄 기호 · 「적용 · 값 · 기준」 칸 글 대신 조건 값 기호 · 로직 부름 기호(master_equation_sign) · 값 식 숫자 단위 · 있는 계산 변수 연결 바꿈 = 그 줄 식 · 식 속 원자 키보드 글(입력글)
- 화면: 박스 없는 조판 · 반올림 감싸개 · 안 탄 만약 숨김(감싸개 글로 구조 지킴) · 보이는 식 그 자리 고침(contenteditable · 원자 data-tok) · 값 숫자 그 자리 고침(valueEdit)
- 시험 test_801_1 7 통과 · 넓은 왕복 199 로직 중 13 걸림(식 300 자 상한 · 요소 EQ/MO 글 · 표 칸 Q 기호 맞물림) · test_796_2 옛 createFormulaCell 기대 안 고침(멈춤)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 17:50:36 +09:00

100 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
"""수식 마디 기호 다듬기(PLAN 801-1 · 801-2 · 요구 662-4) — 기호 씌운(`master_symbol.apply`) 뒤 · 정의 영역 앞.
보이기만 — 셈 · 엔진 열쇠 · 식(`식` 칸) 안 바꿈.
- 한 마디 줄: 중간 · 결과 줄 식이 표 찾기 · 요소 · 로직 부르기 한 마디뿐이면 그 마디 = 줄 기호 · 줄 `한마디`
(화면은 「q = 0.7」 — 표 칸 글 「적용」 · 로직 이름은 정의 영역에만).
- 로직 부르기 마디 = 기호(부른 로직 결과 기호 + 아래 = 로직 이름 앞말) — 이름은 정의 영역 · 펼침 머리.
- 뜻 없는 표 칸 글(`PLAIN` — 적용 · 값 · 기준)로 지은 표 찾기 기호 = 그 행 조건 값(없으면 표 이름)으로.
- 한 로직 안 겹침 = 아래첨자 끝 숫자(`master_symbol.apply` 와 같은 꼴).
"""
from __future__ import annotations
import master_symbol as msym
PLAIN = {"적용", "값", "기준"}
LEAF = ("찾기", "요소")
def _sign(n: dict) -> str:
return f"{n.get('기호') or ''}_{n.get('아래') or ''}^{n.get('위') or ''}"
def _nodes(tree, out: list[dict]) -> list[dict]:
"""변수 · 블록 마디(블록 속 나무는 따로 다듬음 — 안 들어감)."""
if isinstance(tree, list):
for one in tree:
_nodes(one, out)
elif isinstance(tree, dict):
if tree.get("꼴") in ("변수", "블록"):
out.append(tree)
for k, v in tree.items():
if k != "나무" and isinstance(v, (dict, list)):
_nodes(v, out)
return out
def lone(line: dict) -> bool:
"""줄 식이 표 찾기 · 요소 · 로직 부르기 한 마디뿐인 중간 · 결과 줄."""
tree = line.get("이름식") or {}
one = tree.get("꼴") == "블록" or (tree.get("꼴") == "변수" and tree.get("갈래") in LEAF)
return line.get("갈래") in ("중간", "결과") and one and isinstance(line.get("결과"), dict)
def _block_sign(node: dict) -> tuple[str, str, str]:
sub = node.get("나무") or {}
last = next((x for x in reversed(sub.get("줄") or []) if x.get("갈래") == "결과"), None)
head = (last or {}).get("결과") or {}
sign = head.get("기호") if msym.is_symbol(str(head.get("기호") or "")) else ""
sign = sign or msym.rule(str(node.get("결과단위") or ""), "결과")[0]
return sign, msym.short(str(node.get("이름") or node.get("열쇠") or "")), ""
def _find_sign(node: dict) -> tuple[str, str, str]:
said = [str(v) for v in (node.get("행") or {}).values() if isinstance(v, str) and v]
name = said[-1] if said else str(node.get("표이름") or "")
node["칸글"] = True # 정의 이름 = 표 · 조건 값(칸 글 아님)
node["이름"] = " ".join(x for x in (str(node.get("표이름") or ""), *said[-1:]) if x)
if msym.is_symbol(name):
return name, "", "표"
sign, low, _ = msym.lookup(name, "찾기")
return sign, low, "표"
def settle(out: dict) -> dict:
"""내보낸 수식 한 벌(한 깊이) 다듬기 — 제자리 고침 · 같은 것 돌려줌."""
lines = out.get("줄") or []
for line in lines:
if lone(line):
line["한마디"] = True
head = line["결과"]
line["이름식"] |= {k: head.get(k) or "" for k in ("기호", "아래", "위")}
nodes = _nodes(lines, [])
heads = [x["결과"] for x in lines if isinstance(x.get("결과"), dict)]
used = {_sign(n) for n in [*nodes, *heads, *(out.get("변수표") or [])]}
done: dict[str, tuple[str, str, str]] = {}
for line in lines:
skip = line["이름식"] if line.get("한마디") else None
for node in _nodes(line.get("이름식"), []):
if node is skip:
continue
if node.get("꼴") == "블록":
want = _block_sign
elif node.get("갈래") == "찾기" and node.get("칸") in PLAIN:
want = _find_sign
else:
continue
key = str(node.get("식") or node.get("열쇠"))
if key not in done:
used.discard(_sign(node))
sign, low, up = want(node)
n, base = 1, low
while _sign({"기호": sign, "아래": low, "위": up}) in used:
n += 1
low = base[: msym.SUBMAX - len(str(n))] + str(n)
used.add(_sign({"기호": sign, "아래": low, "위": up}))
done[key] = (sign, low, up)
node["기호"], node["아래"], node["위"] = done[key]
return out