Files
Aislo/M02_MasterTemplete/M02_Mat_Place.py
T
eomsangdonandClaude Opus 5.5 dd9ebad8d1 feat(830-10): 불러오기 재료 찾기를 지역 · 상하차 칸에 맞춤 — 가져온 줄 글은 빌더 규칙으로 판독
- 새 M02_Mat_Place: 가져온 이름 · 규격 → (뺀 이름, 뺀 규격, 지역, 상하차)(material_merge 판독 한 벌) · 고르는 차례 rank
- 고르는 차례 = 상하차 맞음(글 없으면 -) › 값 있는 줄 › 줄 지역 › 전국 · 지역 모름 › 서울 › 경기 › 그 밖(값 가운데에 가까운 줄)
- Elem_Alias(_same · one · region_of) · Hopyo_Match(목록에 지역 · 상하차 · 값 · 이름 같음 = 뺀 이름 + 지역 · 상하차 같음) · Hopyo_Material(_places · 변형 지역 = 지역 칸 · _prefer) · MatSame._pick · MatFind 후보 글 = 지역 칸
- 다시 고르기 · 찾기 창 · 줄 풍선말 후보 글에 지역 · 상하차(M01 placeNote 한 벌)
- 시험: 814_1 · m02_hopyo_match 기대를 지역 칸 꼴로 · 새 지킴 test_830_10_material_region 21
- 불러오기 지킴 812_1 · 814_1 · 815_1 · 817_1 · 827_2 · 827_3 · 828_1 · 828_2 · 778_5 ×2 · 793_2 ×2 · 797_1 ×2 · m02_hopyo_match 통과 · typecheck 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 20:57:23 +09:00

79 lines
3.4 KiB
Python

"""불러오기 재료 지역 · 상하차 한 벌(PLAN 830-10 · 요구 839) — 서버 단독 · 읽기만.
- `line(이름, 규격)` = 가져온 줄 글(경쟁사 이름 · 규격 — 지역 · 인도 조건 글이 그대로 옴)을 M01 재료 표 빌더와
같은 규칙(`material_merge.split_load` · `split_region`)으로 읽음 → {이름, 규격, 지역, 상하차} · 글 없음 = -.
- 우리 줄 = M01 재료 표 지역 · 상하차 칸(이름 글로 읽지 않음).
- `rank(우리 줄, 바라는 것, 가운데 값)` = 같은 품목 줄 여럿에서 고르는 차례 —
상하차가 줄 글과 같음(글 없으면 -) › 값 있는 줄(M01 검색어 고르기와 같음) › 지역: 줄 지역 › 전국(지역 모름 - 포함) › 서울 › 경기 ›
그 밖(값이 가운데 값에 가까운 줄) — 조달청 지역 규칙과 같은 차례(요구 830).
"""
from __future__ import annotations
import re
from statistics import median
from typing import Any
from M01_MasterData import M01_MasterData_Store as m01 # noqa: F401 — scripts 경로를 넣음
import material_merge as mmerge # noqa: E402
NONE = mmerge.NONE
NATION = ("전국", "전지역", NONE)
PRICES = ("물가자료", "유통물가", "물가정보", "거래가격", "일반가격") # 사급 값 칸(조달청 뺌)
def line(name: Any, spec: Any) -> dict[str, str]:
"""가져온 줄 → {이름, 규격(지역 · 인도 조건 글 뺌), 지역, 상하차}."""
n, s, load, _ = mmerge.split_load({"이름": str(name or ""), "규격": str(spec or "")})
n, s, where = mmerge.split_region(n, s)
return {"이름": n, "규격": s, "지역": where, "상하차": load}
def words(where: Any) -> list[str]:
"""지역 글 → 한글 낱말(전국류 뺌) — 「경상북도(칠곡군)」 → 경상북도 · 칠곡군."""
return [w for w in re.findall(r"[가-힣]{2,}", str(where or "")) if w not in NATION]
def hit(where: Any, want: Any) -> bool:
"""우리 지역 글이 줄 지역 글과 맞음 — 같은 글 · 낱말 앞 두 글자가 하나라도 같음(「경북」 · 「경북제일」)."""
if not want or want == NONE:
return False
if str(where) == str(want):
return True
mine = words(want) if isinstance(want, str) else list(want)
return any(a[:2] == b[:2] for a in mine for b in words(where))
def value(row: dict) -> Any:
"""사급 값 칸 다섯 가운데 낮은 값(줄에 「값」 이 있으면 그것) — 없음 = None."""
if "값" in row:
return row["값"]
got = [row[c] for c in PRICES if row.get(c) is not None]
return min(got) if got else None
def middle(rows: list[dict]) -> Any:
got = [v for v in (value(r) for r in rows) if v is not None]
return median(got) if got else None
def rank(row: dict, want_where: Any, want_load: str, mid: Any) -> tuple:
"""고르는 차례 열쇠(작을수록 먼저) — (상하차 다름, 값 없음, 지역 차례, 가운데 값과의 거리)."""
where = str(row.get("지역") or NONE)
if hit(where, want_where):
tier = 0
elif where in NATION or not words(where):
tier = 1
else:
tier = 2 if where.startswith("서울") else 3 if where.startswith("경기") else 4
v = value(row)
gap = (
0.0
if tier < 4 or mid is None
else float("inf")
if v is None
else abs(float(v) - float(mid))
)
return ((row.get("상하차") or NONE) != (want_load or NONE), v is None, tier, gap)