feat(815-1 K1·K2·K3·K5): 불러오기 이음 — EST 코드 · 별칭 칸 · 표기 맞추기 · 견적 줄
- K1 EST 원파일 자재 = 우리 자재 출처 칸 EST 코드로 바로 이음(새 M02_Elem_Alias · 자재 자원 24,219 중 코드 같음 23,981 모두 그 줄) - K2 M01 요소 줄 「별칭」 칸 읽기 — 기계 찾기(옛 별칭 장부 읽기 걷음) · 재료 · 인력 · 유가 · 일위대가 호표 줄(Units · Hopyo_Sangeun 장부 import 뗌) - K3 재료 표기 정규화 정확 일치(M/M · 곱셈표 · 지름 · 괄호 · 빈칸 · 전각 · 지역 꼬리) — 바탕 이름 길보다 먼저(치즐(0.7m3) → 0.2㎥ 줄로 잘못 잇던 것 바로잡음) - K5 견적 · 운임 · 수수료 줄 = 우리 자재면 재료 줄(우리 값) · 아니면 그대로 + 「견적」 표지 · 문서 설명 · 화면 「견적 n」 배지(못 이음 수에서 뺌) - 시험 test_815_1_import_link 새로 · test_812_9 = 옛 장부 별칭 대신 기계 줄 별칭 칸(마스터 다섯은 칸이 비면 시험 동안만 넣음) · 「디젤 엔진」 은 마스터 별칭 묶음으로 옮김 - test_778_5 기계 표(162 · 3 · 25)는 고치기 전 판과 같음 — 812-9 뒤부터 굳힌 수와 다름(이번 고침 무관 · 안 고침) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
과녁 = M01 기계표 전체(EQ) · 부르는 곳 = 불러오기 이음(`M02_Hopyo_Row.m01_picks` · `M02_San_Emit._m01`) ·
|
||||
일위대가 호표(`M02_Hopyo_Elem.machine(s)` · `M02_Hopyo_Fixed._eqs`) · 연결 찾기(`M02_Doc_Match_Note`).
|
||||
차례:
|
||||
1. 별칭 장부(`M02_Hopyo_Ledger` · 마스터 층 + 지금 층 · 짝 갈래 기계) — 이름 + 규격 열쇠 = 그 EQ ·
|
||||
이름만(규격 빈) 열쇠 = 그 EQ 이름으로 바꿔 2 로
|
||||
1. 별칭(M01 기계 줄 「별칭」 칸 · 815-1 `M02_Elem_Alias`) — 「이름 규격」 통째 별칭 = 그 EQ(여럿 =
|
||||
후보 여럿) · 이름만 별칭 = 그 EQ 기종으로 바꿔 2 로
|
||||
2. 기종 = EQ 이름(괄호 뗌) · 괄호 붙임 · 상세구분과 같은 글 › 그 글을 품은 EQ(표기 정규화 `norm`)
|
||||
3. 괄호 낱말 — 기계표 괄호에 있는 낱말(무한궤도 · 타이어 · 자주식 …)만 거름 · 표에 없는 낱말(발파 · 리핑)은 안 봄
|
||||
4. 규격 = 수 + 단위(범위 · 여럿) 모두 EQ 규격에 같은 값(단위 한쪽 없음 = 봄) › 없으면 EQ 범위 안
|
||||
@@ -20,7 +20,6 @@ import re
|
||||
import time
|
||||
import unicodedata
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
@@ -222,38 +221,14 @@ def parts(name: Any, spec: Any = "") -> list[tuple[str, str]]:
|
||||
return [(n, s or first) for n, s in out]
|
||||
|
||||
|
||||
# ── 별칭 장부 ─────────────────────────────────────────────────────────
|
||||
def _alias_rows() -> dict[tuple[str, str], list[str]]:
|
||||
"""(이름, 규격) 정규화 → EQ 키들 — 마스터 층 + 지금 층 별칭 장부 기계 짝."""
|
||||
from M02_MasterTemplete import M02_Hopyo_Store as hopyo_store
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||||
|
||||
here, top = Path(store.root()), Path(store.FOLDER)
|
||||
folders = [here] + ([top] if here != top else [])
|
||||
files = [(f, hopyo_store._dir(f) / f"{hopyo_store.MEMORY}.json") for f in folders]
|
||||
stamp = tuple((str(f), p.stat().st_mtime_ns if p.is_file() else 0) for f, p in files)
|
||||
return _alias_read(stamp)
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def _alias_read(stamp: tuple) -> dict[tuple[str, str], list[str]]:
|
||||
from M02_MasterTemplete import M02_Hopyo_Ledger as ledger
|
||||
|
||||
out: dict[tuple[str, str], list[str]] = {}
|
||||
for folder, _ in stamp:
|
||||
for row in ledger.read(folder).values():
|
||||
pairs = row.get("짝") or []
|
||||
eqs = [str(p["키"]) for p in pairs if p.get("갈래") == "기계" and p.get("키")]
|
||||
if row.get("갈래") != "짝" or not eqs:
|
||||
continue
|
||||
origin = row.get("원래") or {}
|
||||
out.setdefault((norm(origin.get("품명")), norm(_clean(origin.get("규격")))), eqs)
|
||||
return out
|
||||
|
||||
|
||||
# ── 별칭(M01 기계 줄 「별칭」 칸 · 815-1) ───────────────────────────────────
|
||||
def alias(name: Any, spec: Any) -> list[str]:
|
||||
"""별칭 장부 기계 짝 — 이름 + 규격 열쇠(규격 속 할증 글은 뺌) · 없으면 []."""
|
||||
return _alias_rows().get((norm(name), norm(_clean(spec))), [])
|
||||
"""M01 기계 줄 별칭(`M02_Elem_Alias`) — 규격이 있으면 「이름 규격」 통째 별칭(규격 속 할증 글은 뺌) ·
|
||||
규격 빔 = 이름 별칭 · 없으면 []."""
|
||||
from M02_MasterTemplete import M02_Elem_Alias as ea
|
||||
|
||||
rows = ea.book()["별칭"].get("EQ", {})
|
||||
return list(rows.get(ea.am.norm(name) + ea.am.norm(_clean(spec)), []))
|
||||
|
||||
|
||||
# ── 찾기 ──────────────────────────────────────────────────────────────
|
||||
@@ -280,18 +255,19 @@ def _ans(kind: str, rows: list[Row], query: str, why: str = "") -> dict[str, Any
|
||||
def find(name: Any, spec: Any = "") -> dict[str, Any]:
|
||||
"""기계 하나(조합 아님) → `{판정, 키, 후보, 찾기어, 까닭, 수}`."""
|
||||
rows_by = table()[2]
|
||||
hit = alias(name, spec)
|
||||
if len(hit) == 1 and hit[0] in rows_by:
|
||||
r = rows_by[hit[0]]
|
||||
return _ans(ALIAS, [r], str(r.raw.get("이름")))
|
||||
hit = [rows_by[k] for k in alias(name, spec) if k in rows_by]
|
||||
if hit: # 별칭 하나 = 그 EQ · 여럿 = 후보 여럿
|
||||
if len(hit) == 1:
|
||||
return _ans(ALIAS, hit, str(hit[0].raw.get("이름")))
|
||||
return _ans(MANY, hit, _query(hit, hit[0].base), f"후보 {len(hit)}")
|
||||
base = split_name(name)[0]
|
||||
_, groups, specs = split_name(f"{name or ''} {spec or ''}") # 규격 괄호 낱말 「3.6m(일반용)」
|
||||
groups.append(
|
||||
_words(_TOKEN.sub(" ", _PAREN.sub(" ", _clean(spec))))
|
||||
) # 규격 글 낱말 「탑승유압식」
|
||||
named = alias(name, "")
|
||||
if len(named) == 1 and named[0] in rows_by: # 이름만 별칭 = 그 EQ 기종으로
|
||||
base = rows_by[named[0]].base
|
||||
named = [rows_by[k] for k in alias(name, "") if k in rows_by]
|
||||
if named and len({r.base for r in named}) == 1: # 이름만 별칭 = 그 EQ 기종으로
|
||||
base = named[0].base
|
||||
mine = tokens(" ".join(specs))
|
||||
kinds = kind_rows(base)
|
||||
known = table()[1]
|
||||
@@ -307,7 +283,7 @@ def find(name: Any, spec: Any = "") -> dict[str, Any]:
|
||||
same = [r for r in rows if spec_fit(mine, r.spec) == "같음"]
|
||||
got = same or [r for r in rows if spec_fit(mine, r.spec) == "안"]
|
||||
if len(got) == 1: # 이름만 별칭으로 기종을 정했으면 「별칭」
|
||||
return _ans(ALIAS if len(named) == 1 else LINKED, got, str(got[0].raw.get("이름")))
|
||||
return _ans(ALIAS if named else LINKED, got, str(got[0].raw.get("이름")))
|
||||
if got:
|
||||
return _ans(MANY, got, _query(got, base), f"후보 {len(got)}")
|
||||
if not kinds:
|
||||
@@ -326,12 +302,7 @@ def _gap(mine: list, theirs: list) -> float:
|
||||
|
||||
|
||||
def find_all(name: Any, spec: Any = "") -> list[dict[str, Any]]:
|
||||
"""기계 글 → 부분마다 `find` + {이름, 규격}(조합 = 둘 이상) · 글 통째 별칭(짝 여럿)이 먼저."""
|
||||
whole = alias(name, spec)
|
||||
rows_by = table()[2]
|
||||
if len(whole) > 1 and all(k in rows_by for k in whole):
|
||||
made = [_ans(ALIAS, [rows_by[k]], str(rows_by[k].raw.get("이름"))) for k in whole]
|
||||
return [{**x, "이름": str(name or ""), "규격": str(spec or "")} for x in made]
|
||||
"""기계 글 → 부분마다 `find` + {이름, 규격}(조합 = 둘 이상)."""
|
||||
out: list[dict[str, Any]] = []
|
||||
for n, s in parts(name, spec):
|
||||
if out and s and not split_name(n)[2] and s == out[0]["규격"] and out[0]["키"]:
|
||||
|
||||
Reference in New Issue
Block a user