fix(B09): 분류 딱지 행에서 이름을 둘째 칸으로 읽음 — 자재·장비가 통째로 빠지던 자리
배분 창이 「초류종자살포 배합이 네 일위대가에 있나」를 물어 확인하다 **구멍을 찾음.** - 품셈 표 중 **첫 칸이 분류 딱지**(「자재」·「장비」)이고 **이름이 둘째 칸**인 것이 있음: `['자재', '종 자', '', 'kg', '0.025']` · `['장비', '종자살포기', '2,500-3,000ℓ', …]`. 첫 칸만 보고 읽어 **그 표의 자재·장비가 통째로 빠지고 있었음** — 씨앗뿜어붙이기에서 종자·비료·피복제·침식안정제·색소·장비 3종이 다 빠지고 **보통인부 한 줄만** 남았음. - 첫 칸이 분류 딱지면 이름을 둘째 칸에서 읽고, 값도 그 뒤 칸에서 찾게 고침. - **매칭 106 → 116**(노무 100 → 110). 산출 파일 다시 냄. **⚠ 그래도 배합은 아직 못 실림 — 원인은 사급 자재 단가 미결임** - 종자·복합비료·화이버·합성접착제·색소가 **관급 카탈로그에 없음**(임도 자재가 관급에 없다는 앞선 발견과 같은 자리). 장비 3종(종자살포기·트럭·물탱크)도 기종 카탈로그에 없음. - **다만 이제 못 맞춘 목록에는 남음** — 구멍을 목록으로 드러내는 규칙 그대로. 시험으로 못 박음(`test_seeding_materials_are_listed_not_dropped`). - ⇒ 사면 4계열의 배합이 **B09 일위대가 몫**인 것은 맞으나, **사급 단가가 들어오기 전에는 못 세움.** 「자재총괄에 이을 것이 없다」는 메인 판정은 유지되고, 그 자재는 **㉡ 6번 슬롯 수동 입력 목록**으로 감(야면석·막자갈·고임돌·물구멍에 이어). 자체검증 — 신규 2건 포함 `pytest tmp/tests/ -q` **136 passed** · ruff 통과. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,13 @@ _CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_RE_SPEC = re.compile(r"[((]([^))]+)[))]|(\d+(?:\.\d+)?\s*(?:톤|ton|㎥|m3|㎡|㎜|mm|HP|kW))")
|
||||
_RE_NUMBER = re.compile(r"^-?\d+(?:,\d{3})*(?:\.\d+)?$")
|
||||
|
||||
#: 첫 칸이 **분류 딱지**이고 이름이 둘째 칸에 오는 표가 있다.
|
||||
#: 예 — `['자재', '종 자', '', 'kg', '0.025']` · `['장비', '종자살포기', …]`.
|
||||
#: 이 표를 첫 칸만 보고 읽으면 **자재·장비가 통째로 빠진다**(2026-09-07 실측 —
|
||||
#: 씨앗뿜어붙이기에서 종자·비료·피복제·침식안정제·색소·장비 3종이 다 빠지고
|
||||
#: 보통인부 한 줄만 남았다).
|
||||
_GROUP_LABELS = ("자재", "장비", "인력", "노무", "재료", "기계")
|
||||
|
||||
#: 표 머리글·소계 행의 첫 칸에 오는 말. 자원이 아니므로 `unmatched` 로도 안 올린다.
|
||||
#: 이것을 안 거르면 못 맞춘 목록이 머리글로 가득 차 **쓸 수 없는 목록**이 된다.
|
||||
#: ⚠ **부분일치로 보면 안 된다.** 「계」를 부분일치로 잡으면 `건설기계운전사`·`비계공`·
|
||||
@@ -447,11 +454,16 @@ def match_table(
|
||||
cells = [str(c) for c in row]
|
||||
if not cells:
|
||||
continue
|
||||
# 첫 칸이 분류 딱지(「자재」·「장비」)면 **이름은 둘째 칸**이다.
|
||||
name_cell = cells[0]
|
||||
value_cells = cells[1:]
|
||||
if _normalize(name_cell) in _GROUP_LABELS and len(cells) > 1:
|
||||
name_cell = cells[1]
|
||||
value_cells = cells[2:]
|
||||
|
||||
# 숫자 셀이 없는 행은 자원 줄이 아니다(제목·설명 행) — 목록에 안 올린다.
|
||||
amount_cell = next(
|
||||
(parse_amount(c) for c in cells[1:] if parse_amount(c) is not None), None
|
||||
(parse_amount(c) for c in value_cells if parse_amount(c) is not None), None
|
||||
)
|
||||
if amount_cell is None:
|
||||
continue
|
||||
@@ -459,7 +471,7 @@ def match_table(
|
||||
# ⚠ **카탈로그 조회를 먼저 한다.** 이름 필터를 앞에 두면 필터가 넓을 때
|
||||
# 정상 자원이 조용히 사라진다(2026-09-07 실측 — 부분일치 필터가 매칭 14건을
|
||||
# 지우고 있었음). 카탈로그에 있는 이름은 **정의상 자원**이다.
|
||||
entry = _resolve_cell(catalog, name_cell, cells)
|
||||
entry = _resolve_cell(catalog, name_cell, [name_cell, *value_cells])
|
||||
if entry is None:
|
||||
if is_non_resource_label(name_cell):
|
||||
continue # 머리글·소계 — 못 맞춘 목록에도 안 올린다
|
||||
|
||||
Reference in New Issue
Block a user