fix(b08): [주] 추출 오염 걷어냄 — 절 제목이 목록 줄로 적혀 제목·남의 [주]까지 끌어오고 있었음

랩탑 서브 전수 확인(읽기만)으로 드러난 것. 원문이 절 제목을 「- 3. 노상 및 노반재료」·
「- 라. 체적환산계수(f)표」처럼 **목록 줄**로 적는데, [주] 이어짐 「- ②」와 같은 「-」로 시작해서
멈춤이 「#」과 표뿐이던 내 추출이 제목도 다음 절 [주]도 통째로 먹었음.

- 멈추는 자리 셋 — 다음 절(`#`) · **목록꼴 제목** · 두 번째 `[주]`
  · 목록꼴 = `- 숫자.` · `- 가.` · `- (1)` · `- (가)` · `- 가)` (가나다…하 열넷만 — 「등)」·「(인)」 제외)
  · 근거: 원문 [주]는 ①② 꼴이거나 번호 없음뿐 — 「1.」·「가.」 꼴 [주]는 1,420 중 0건
- ⚠ **[주] 를 만나기 전에도 같은 규칙** — 제 [주] 가 없는 표가 제목을 건너 **남의 [주] 를 빌려오던 것**
  을 막음(F0009 가 강재류 [주]를 달고 있었음). 남의 계수가 붙는 쪽이 더 나쁨
- ⚠ 쪽이 넘어가며 줄 **끝에** 눌어붙은 쪽번호·장 제목 131줄은 **줄 안에서** 잘라 냄
  (「…따른다.11제1장 적용기준」 — 「숫자+제N장」이 붙어 오는 꼴은 본문에 없음)
- 걷힌 양 — 산림 표 320 → 306 · 줄 1,162 → 1,082 / 건설 표 1,761 → 1,106 · 줄 6,928 → 4,162
- 금액 관련 [주]는 그대로 — 발파 가산 20%(F0245) · 공구손료 3%(F0395) 확인
- 원문 셀은 여전히 한 칸도 안 바뀜(산림 453/453 · 건설 2,192/2,192)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsGw1Dz9HmhuAxGisxmDPF
This commit is contained in:
2026-09-17 23:40:32 +09:00
co-authored by Claude Opus 5
parent c3da333e61
commit 32c4c5cf28
6 changed files with 1069 additions and 4531 deletions
@@ -292,10 +292,33 @@ def basis_from_source(lines: list[str], line_no: int) -> tuple[float | None, str
return None, None
#: 표 아래 `[주]` 덩어리를 어디까지 볼 것인가. 다음 표·다음 절을 만나면 멈춘다.
#: 표 아래 `[주]` 덩어리를 어디까지 볼 것인가. 다음 표·다음 절·**목록꼴 제목**을 만나면 멈춘다.
NOTES_LOOKAHEAD = 40
_NOTE_START = ("[주]", "[ 주 ]", "[주")
_NOTE_CONT = ("-", "·", "")
#: 가나다…하 열넷만. ⚠ 넓히면 「등)」·「(인)」 같은 글이 제목으로 잡힌다.
_ORDER = "가나다라마바사아자차카타파하"
#: ⚠⚠ **원문이 절 제목을 목록 줄로 적는다** — 「- 3. 노상 및 노반재료」·「- 라. 체적환산계수(f)표」.
#: [주] 이어짐 「- ②」와 **같은 「-」로 시작**해서, 멈춤이 「#」과 표뿐이면 제목도 다음 절 [주]도
#: 통째로 끌어온다(2026-09-17 랩탑 서브 전수 확인: 산림 28표 41줄 · 건설 293표 541줄).
#: ⚠ 원문 [주]는 **①② 꼴이거나 번호 없음뿐** — 「1.」·「가.」 꼴 [주]는 1,420 중 0건이다.
#: 그래서 이 꼴이 오면 **거기서부터는 남의 글**이다.
NOTE_STOP_RE = re.compile(rf"^-\s*(?:\d+\.|[{_ORDER}]\.|\(\d+\)|\([{_ORDER}]\)|[{_ORDER}]\))")
#: ⚠ **쪽이 넘어가며 쪽번호와 장 제목이 [주] 줄 **끝에** 눌어붙은 자리** — 「…따른다.11제1장 적용기준」.
#: 줄 단위로는 못 자른다(줄 한복판에서 갈림). 「숫자 + 제N장」이 **띄어쓰기 없이** 붙는 꼴은
#: 본문에 없으므로 이 자리를 잘라 낸다(건설 131줄 · 2026-09-17 랩탑 서브 ⓑ).
PAGE_BREAK_RE = re.compile(r"\d{1,4}제\d+장.*$")
def trim_page_break(text: str) -> str:
"""줄 끝에 눌어붙은 쪽번호·장 제목을 떼어 낸다. 없으면 그대로."""
return PAGE_BREAK_RE.sub("", text).rstrip()
def _is_note_head(text: str) -> bool:
return text.startswith(_NOTE_START)
def notes_from_source(lines: list[str], line_no: int) -> list[str]:
@@ -305,25 +328,35 @@ def notes_from_source(lines: list[str], line_no: int) -> list[str]:
공구손료 3% · 고소 감속 9% …). 마스터가 그 글을 안 싣고 있어 받는 쪽이 볼 길이 없었다
(2026-09-17 안티그래비티 전수 대조 ④). **읽기만 싣는다 — 여기서 셈하지 않는다.**
⚠ 다음 (`|`)나 다음 절(`#`)을 만나면 멈춘다. 남의 [주]를 물어 오면 조용히 틀린다.
멈추는 자리 셋 — 다음 (`#`) · **목록꼴 제목**(`NOTE_STOP_RE`) · 두 번째 `[주]`.
⚠ **[주] 를 만나기 전에도 같은 규칙을 건다** — 제 [주] 가 없는 표가 제목을 건너
남의 [주] 를 빌려오던 것을 막는다(산림 11표 · 건설 207표). 남의 계수가 붙는 쪽이 더 나쁘다.
⚠ 빈 줄·들여쓰기로는 못 가른다 — 제목이 빈 줄 없이 붙고 건설 들여쓰기가 제멋대로다.
"""
out: list[str] = []
started = False
body_done = False
for index in range(line_no, min(len(lines), line_no + NOTES_LOOKAHEAD)):
text = lines[index].strip()
if text.startswith("#"):
break
if NOTE_STOP_RE.match(text):
break # 목록꼴 제목 — 여기서부터는 남의 글이다
if text.startswith("|"):
if started:
break # [주] 뒤에 새 표가 왔다 — 여기까지가 이 표의 [주]
continue # 아직 표 본문 안이다
if started or body_done:
break # 새 표가 왔다 — 이 표의 [주] 는 여기까지
continue # 아직 표 본문 안이다
if not text:
continue
if text.startswith(_NOTE_START):
if _is_note_head(text):
if started:
break # 두 번째 [주] — 다음 표 것이다
started = True
out.append(text)
elif started and text.startswith(_NOTE_CONT):
out.append(text)
out.append(trim_page_break(text))
continue
body_done = True # 표 본문은 끝났다(글줄이 나왔다)
if started and text.startswith(_NOTE_CONT):
out.append(trim_page_break(text))
elif started:
break # [주] 덩어리가 끝났다
return out
@@ -1,7 +1,7 @@
{
"schema_version": "1.0",
"dataset_id": "data_work_item_master_manifest",
"generated_at": "2026-09-17T23:15:06+09:00",
"generated_at": "2026-09-17T23:33:15+09:00",
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
"source": {
"dataset_id": "pum_forest",
@@ -12,8 +12,8 @@
"files": [
{
"file": "work_item_master_2026-01-01.json",
"sha256": "463a54f13ef9d9bd7de30a43c1d43033f6235ab2912cd6fa63c266b0c040a3c5",
"size_bytes": 1079474
"sha256": "3a4e46ea367e9f8ca93c6e9ef95226930db4a495ec0f92f6cafaaf805cdd3e4b",
"size_bytes": 1072203
},
{
"file": "form_undetermined_2026-01-01.json",
@@ -1,7 +1,7 @@
{
"schema_version": "1.0",
"dataset_id": "data_work_item_master_manifest",
"generated_at": "2026-09-17T23:15:58+09:00",
"generated_at": "2026-09-17T23:34:03+09:00",
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
"source": {
"dataset_id": "pum_const",
@@ -12,8 +12,8 @@
"files": [
{
"file": "const_work_item_master_2026-01-01.json",
"sha256": "b30084103c03cdc837ab456b33fdf0eaac1319311f38549ca493d269a1ac2859",
"size_bytes": 4863086
"sha256": "0ddceecdfd3772c236b8e828f89cadfe978982eb0f4608a9fa0a2581b3f00e6e",
"size_bytes": 4453384
},
{
"file": "const_form_undetermined_2026-01-01.json",
File diff suppressed because it is too large Load Diff
@@ -4,7 +4,7 @@
"effective_date": "2026-01-01",
"pum_edition": "2026-01-01",
"toc_edition": "산림청고시제2025-82호",
"generated_at": "2026-09-17T23:15:06+09:00",
"generated_at": "2026-09-17T23:33:15+09:00",
"dataset_version": {
"dataset_id": "pum_forest",
"effective_date": "2026-01-01",
@@ -983,8 +983,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 암(경암ㆍ보통암ㆍ연암)을 토사와 혼합성토할 때는 공극채움으로 인한 토사량을 계상할 수 있다.",
"- 라. 체적환산계수(f)표"
"[주] 암(경암ㆍ보통암ㆍ연암)을 토사와 혼합성토할 때는 공극채움으로 인한 토사량을 계상할 수 있다."
],
"condition_note": [
"종 별",
@@ -1834,8 +1833,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 속채움 재료의 경우에도 이 값을 적용한다.",
"- 3. 노상 및 노반재료(선택층, 보조기층, 기층 등)"
"[주] 속채움 재료의 경우에도 이 값을 적용한다."
],
"condition_note": [
"종 류",
@@ -1893,10 +1891,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 이형철근의 경우, 해당 공사 또는 구조물의 시공실적에 따라 조정하여 적용할 수 있다.",
"- 6. 기타재료"
],
"notes": [],
"condition_note": [
"종 류",
"할 증 률 ()"
@@ -1938,10 +1933,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 이형철근의 경우, 해당 공사 또는 구조물의 시공실적에 따라 조정하여 적용할 수 있다.",
"- 6. 기타재료"
],
"notes": [],
"condition_note": [
"종 류",
"할 증 률 ()"
@@ -1972,8 +1964,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 이형철근의 경우, 해당 공사 또는 구조물의 시공실적에 따라 조정하여 적용할 수 있다.",
"- 6. 기타재료"
"[주] 이형철근의 경우, 해당 공사 또는 구조물의 시공실적에 따라 조정하여 적용할 수 있다."
],
"condition_note": [
"종 류",
@@ -4496,10 +4487,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 잡품은 엔진유, 기어유, 그리스 등 기타소모품에 해당하며 주 연료비에 대하여 금액비율로 적용한다.",
"- 5. 천공기"
],
"notes": [],
"condition_note": [
"기계명(주재료)",
"주연료 (/일,대)",
@@ -4532,8 +4520,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 잡품은 엔진유, 기어유, 그리스 등 기타소모품에 해당하며 주 연료비에 대하여 금액비율로 적용한다.",
"- 5. 천공기"
"[주] 잡품은 엔진유, 기어유, 그리스 등 기타소모품에 해당하며 주 연료비에 대하여 금액비율로 적용한다."
],
"condition_note": [
"기계명(주재료)",
@@ -5040,8 +5027,7 @@
"notes": [
"[주] ① 주두부 직경이 클수록 소금처리량을 증가시킨다.",
"- ② 주재료비(소금)의 10%를 잡품으로 추가하여 적용한다.",
"- ③ 잡품에는 나무젓가락 및 페인트 등 소모품 포함한다.",
"- 3. 뿌리제거(100본당)"
"- ③ 잡품에는 나무젓가락 및 페인트 등 소모품 포함한다."
],
"condition_note": [
"주두부직경(㎝)",
@@ -7193,8 +7179,7 @@
"notes": [
"[주]① 벌도목 평균경급이 20cm 미만일 경우 10%, 2030cm일 경우 5%를 할증한다.",
"- ② 산불피해지에서 산불피해목을 벌목할 경우 20%를 할증한다.",
"- ③ 그 외 할인․할증은 경사도(1-4-5), 장애물의 종류와 정도(1-4-8)를 적용한다.",
"- 3. 박피품은 별도 적용하여야 한다. 다만 작업조건에 따라 1일 작업량은 변동 적용한다."
"- ③ 그 외 할인․할증은 경사도(1-4-5), 장애물의 종류와 정도(1-4-8)를 적용한다."
],
"condition_note": [
"(단위 : ㎥/1인/1일)"
@@ -11917,11 +11902,7 @@
],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] ① 「도로비탈면 녹화공사의 설계및 시공 지침 2.7 종자배합설계(2009)」 참조한다.",
"- ② 기타 적용지역이란 자연경관복원형의 복원목표가 적용되지 않는 지역을 말한다.",
"- ③ 해안생태계지역에서는 해안에 적합한 종자배합을 하고, 외래도입초종이 10%를 상회하지 않도록 한다."
],
"notes": [],
"condition_note": [
"복원목표",
"식 생 구 분",
@@ -14411,8 +14392,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] ha당 원목재적 150㎥까지의 경우이며, 초과 시 “인공림 모두베기”를 적용한다.",
"- 2. 인공림 모두베기"
"[주] ha당 원목재적 150㎥까지의 경우이며, 초과 시 “인공림 모두베기”를 적용한다."
],
"condition_note": [
"구 분",
@@ -14465,9 +14445,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 경사도는 1개 기번 전임지의 평균경사도다."
],
"notes": [],
"condition_note": [
"경사",
"어려움(15˚ 미만)",
@@ -18049,11 +18027,7 @@
],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주]① 조경용(전정) 소나무 또는 가지나 잎이 적은 소나무류는 주입량을 적게한다.",
"- ② 가슴높이 지름 100㎝이상의 대형목은 수목의 가치, 활력도 등을 고려하여 상단부 가지 주입 및 가압방식 적용한다.",
"- ③ 매개충나무주사를 실행할 시 30%를 가산한다."
],
"notes": [],
"condition_note": [
"가슴높이 지름(㎝)",
"천공수 (개)",
@@ -20656,8 +20630,7 @@
"notes": [
"[주]① 1일 살포면적 소형헬기 160ha, 대형헬기 400ha 기준이다.",
"- ② 사전조사는 민원사항, 위험물, 유조차 진입 등 조사, 도면작성 등을 위한 품이다.",
"- ③ 실제 사용하지 않는 품은 적용 시 제외한다.",
"- 2. 약제살포량"
"- ③ 실제 사용하지 않는 품은 적용 시 제외한다."
],
"condition_note": [
"구 분",
@@ -20763,9 +20736,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 기종별 헬기 운행안전을 고려하여 약제원액과 희석제 등 1회 총 살포량을 말한다."
],
"notes": [],
"condition_note": [
"구 분",
"희석배수",
@@ -21057,8 +21028,7 @@
"- ④ 비행준비과정은 비행 전 안전점검, 지자기 보정 등 비행 전 기체의 준비과정을 말한다.",
"- ⑤ 산록에서 산정부 방향의 복합사면은 경사도의 변화폭이 20% 이상의 경우를 할증한다.",
"- ⑥ 평균 작업구역 면적은 개소 간 이격거리 50m 이내일 경우 동일 작업구역으로 한다.",
"- ⑦ 할인․할증은 작업구역(1-4-4), 경사도(1-4-5, 평균경사도), 방제지 사면(1-4-20), 방제지 접근성(1-4-21)을 반영한다.",
"- 2. 무인 멀티콥터"
"- ⑦ 할인․할증은 작업구역(1-4-4), 경사도(1-4-5, 평균경사도), 방제지 사면(1-4-20), 방제지 접근성(1-4-21)을 반영한다."
],
"condition_note": [
"구 분",
@@ -21252,8 +21222,7 @@
"차량살포 (동력분무기)"
],
"notes": [
"[주] 사전조사는 민원사항, 위험물, 방제차 진입 등에 대한 조사이다.",
"- 2. 지상살포 희석배수별 약제소요량"
"[주] 사전조사는 민원사항, 위험물, 방제차 진입 등에 대한 조사이다."
],
"condition_note": [
"구 분",
@@ -23025,8 +22994,7 @@
"notes": [
"[주]① 장비는 대형브레이커와 무한궤도 굴착기(0.7㎥)를 적용하며, 100% 기계를 반영한다.",
"- ② Q=(1.6+3.3)/2=2.45㎥/m",
"- ③ 구조물 단위부피의 0.8%를 철근부피로 가정하여 산정하며, 산정량의 80%를 고재 처리한다.",
"- 2. 철근절단"
"- ③ 구조물 단위부피의 0.8%를 철근부피로 가정하여 산정하며, 산정량의 80%를 고재 처리한다."
],
"condition_note": [
"구 분",
@@ -23063,12 +23031,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주]① 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.",
"- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값 적용한다.",
"- 4. 고철공제 : A=1㎥×0.008×7,850kg/㎥×80% = 50.24 kg/㎥ ≒50 kg/㎥",
"[주] 「건설공사 표준품셈 공통부문, 8-2-13 대형브레이커(2025)」, 「건설공사 표준품셈 유지관리부문, 3-1-3 철골재 철거(인력)(2025)」, 「건설공사 표준품셈 유지관리부문, 3-1-4 철골재 철거(기계)(2025)」, 「건설공사 표준품셈 공통부문, 1-2-3 토질, 3. 체적환산계수적용(2025)」, 「국토건설 설계실무요령, 수량산출요령(2021)」 참조한다"
],
"notes": [],
"condition_note": [
"구 분",
"단위",
@@ -23146,14 +23109,7 @@
"variant_key": [],
"notes": [
"[주]① 장비는 대형브레이커와 무한궤도 굴착기(0.7㎥)를 적용하며, 100% 기계를 반영한다.",
"- ② Q=(1.4+2.7)/2=2.05㎥/m",
"- 2. 철근절단 : 철근콘크리트(T=30㎝ 미만)품을 적용한다.",
"- 3. 집토 : Q=3600×q×k×f×E/㎝= ㎥/시간",
"[주]① 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.",
"- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값 적용한다.",
"- 4. 고철공제 : A=1㎥×0.008×7,850kg/㎥×80% = 50.24 kg/㎥≒50 kg/㎥",
"[주]① 적사 및 운반은 폐기물 상차 및 운반비에서 적용한다.",
"- ② 「건설공사 표준품셈 유지관리부문, 3-1-3 철골재 철거(인력)(2025)」, 「건설공사 표준품셈 유지관리부문., 3-1-4 철골재 철거(기계)(2025)」 참조한다"
"- ② Q=(1.4+2.7)/2=2.05㎥/m"
],
"condition_note": [
"구 분",
@@ -23303,10 +23259,7 @@
"[주]① 장비는 대형브레이커와 무한궤도 굴착기(0.7㎥)를 적용하며, 100% 기계를 반영한다.",
"- ② Q=(3.3+5.9)/2=4.6㎥/시간",
"- ③ 임도의 구조개량(평면선형, 종단선형) 공사에 주로 적용한다.",
"- ④ 사용 기계는 공사의 규모, 난이도 등을 고려하여 선정하며, 「건설공사 표준품셈 공통부문, 8-2-13 대형브레이커(2025)」 참조한다.",
"- 2. 집토 : Q=3600×q×k×f×E/㎝= ㎥/시간",
"[주]① 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.",
"- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값 적용한다."
"- ④ 사용 기계는 공사의 규모, 난이도 등을 고려하여 선정하며, 「건설공사 표준품셈 공통부문, 8-2-13 대형브레이커(2025)」 참조한다."
],
"condition_note": [
"구 분",
@@ -23361,11 +23314,7 @@
"variant_key": [],
"notes": [
"[주]① 장비는 대형브레이커와 무한궤도 굴착기(0.7㎥)를 적용하며, 100% 기계를 반영한다.",
"- ② Q=16㎥/시간",
"- 2. 집토 : Q=3600×q×k×f×E/㎝= ㎥/시간",
"[주]① 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.",
"- ② 굴착기작업능력은 무근콘크리트(T=30㎝미만) 값을 적용한다.",
"- ③ 「건설공사 표준품셈 공통부문, 8-2-13 대형브레이커(2025)」 참조한다."
"- ② Q=16㎥/시간"
],
"condition_note": [
"구 분",
@@ -26355,8 +26304,7 @@
"notes": [
"[주]① 공기압축기는 3.5㎥/분, 소형브레이커는 1㎥/분, 굴착기는 0.7㎥를 기준한 것이다.",
"- ② 풍화암 절토면 고르기에 있어 소형브레이커를 사용할 시는 연암 고르기 품을 준용할 수 있다.",
"- ③ 소형브레이커 조작 인력품은 착암공으로 한다.",
"- 2. 성토면 고르기"
"- ③ 소형브레이커 조작 인력품은 착암공으로 한다."
],
"condition_note": [
"토 질 별",
@@ -28052,8 +28000,7 @@
"variant_key": [],
"notes": [
"[주]① 블록 및 제자재는 운반차량의 적하단위, 재적중량 및 운반자재의 형태 치수를 고려하여 재적량을 검토한다.",
"- ② 모노레일용 바스켓 차량이나 보통 차량을 사용한 자재의 운반량은 다음을 표준으로 한다.",
"- 나. 1사이클의 소요시간(cm)"
"- ② 모노레일용 바스켓 차량이나 보통 차량을 사용한 자재의 운반량은 다음을 표준으로 한다."
],
"condition_note": [
"구 분",
@@ -28095,8 +28042,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 차량에 자재를 싣고 내리는 1회당의 소요시간",
"- (2) 운반시간()"
"[주] 차량에 자재를 싣고 내리는 1회당의 소요시간"
],
"condition_note": [
"구 분",
@@ -28132,9 +28078,7 @@
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 본 품셈은 자재의 적재, 짐부리기 및 운전조작을 실시하는 것이다.",
"- 3. 단가표",
"- 가. 모노레일 가설ㆍ철거단가표"
"[주] 본 품셈은 자재의 적재, 짐부리기 및 운전조작을 실시하는 것이다."
],
"condition_note": [
"직 종",
@@ -28171,8 +28115,7 @@
"variant_key": [],
"notes": [
"[주] ① 기타비용은 공구류(유압벤더, 라체트 스패너 등)의 비용이며, 노무비의 합계액에 위의 표의 비율을 곱하여 얻은 금액을 상한으로 계상한다.",
"- ② 모노레일 본기ㆍ차체를 받치고 있는 부분ㆍ레일ㆍ지지대는 임대료 및 견적으로 한다.",
"- 나. 모노레일 운전 단가표"
"- ② 모노레일 본기ㆍ차체를 받치고 있는 부분ㆍ레일ㆍ지지대는 임대료 및 견적으로 한다."
],
"condition_note": [
"명 칭",
@@ -29021,10 +28964,7 @@
"special_glyphs": [],
"capacity_formula_here": true,
"variant_key": [],
"notes": [
"[주]① 장비는 덤프트럭(15ton)을 적용한다.",
"- ② 덤프트럭의 작업능력 산정 비교"
],
"notes": [],
"condition_note": [
"구 분",
"적 용",
@@ -32616,8 +32556,7 @@
"- ⑦ 양생은 양생 방법 및 시간을 고려하여 별도 계상한다.",
"- ⑧ 소모 재료(양생제 등)가 필요한 경우 별도 계상한다.",
"- ⑨ 본 편성인력은 콘크리트 진동기 사용 기준으로 진동기를 사용하지 않는 경우 콘크리트공과 특별인부를 각 1인 제외한다.",
"- ⑩ 공구손료 및 경장비(콘크리트 진동기 등)의 기계경비는 편성인력 노무비의 5%를 적용한다.",
"- 2. 일일 시공량"
"- ⑩ 공구손료 및 경장비(콘크리트 진동기 등)의 기계경비는 편성인력 노무비의 5%를 적용한다."
],
"condition_note": [
"구 분",
@@ -36642,9 +36581,7 @@
],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] 본 기준은 인력 돌쌓기 및 돌붙임에 적용한다."
],
"notes": [],
"condition_note": [
"높 이(m)",
"3 4까지",
@@ -38474,8 +38411,7 @@
"- ④ 규준틀 설치, 돌쌓기, 잡석 채움, 배수 파이프 설치 작업을 포함한다.",
"- ⑤ 뒤채움 품(조약돌)은 “13-3. 기초다짐 및 뒤채움”항을 적용한다.",
"- ⑥ 굴착기 규격은 작업 여건(작업 범위, 위치 등)에 따라 변경할 수 있다.",
"- ⑦ 재료량은 설계수량을 적용한다",
"- 2. 찰붙임"
"- ⑦ 재료량은 설계수량을 적용한다"
],
"condition_note": [
"명 칭",
@@ -39549,8 +39485,7 @@
"[주] ① 본 품은 보통 토사질 상태일 때의 인력 말뚝박기를 기준한 것이며 연토 지질 상태인 경우에는 본 품의 20%를 감하고 자갈층에는 본 품의 30%를 할증한다.",
"- ② 말뚝머리 자르기 품은 본당 보통인부 0.02인을 할증한다.",
"- ③ 9할박기인 경우에는 본 품의 30%를 할증한다.",
"- ④ 말뚝빼기는 본 품의 70%로 한다.",
"- 2. 기초말뚝 박기"
"- ④ 말뚝빼기는 본 품의 70%로 한다."
],
"condition_note": [
"직종",
@@ -39656,19 +39591,7 @@
"special_glyphs": [],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] ① 본 품은 보통 토사질 상태에서 관입길이 6~8할 박기의 경우이며, 3~5할 박기의 경우에는 본 품 중의 개수를 20% 가산한다.",
"- ② 지질상태의 경연에 따라서 본 품의 30% 이내에서 가감할 수 있다.",
"- ③ 인부품에는 말뚝머리 자르기를 포함한다.",
"- ④ 콘크리트 말뚝박기의 경우에는 1일 시공개수를 20% 가산한다.",
"- ⑤ 원동기에 전력을 사용할 때에는 경유 대신 전력량 0.75KWH/HP/hr를 계상한다.",
"- ⑥ 항타 시설의 조립 및 해체는 별도로 계상한다.",
"- ⑦ 윈치 및 발동기의 손료는 별도로 계상하고 기타 시설은 인력품에 포함되어 있다.",
"- ⑧ 계항인 경우에는 선타항의 길이를 표준으로 하여 그 품의 50%를 가산한다.",
"- ⑨ 잡재료(잡유 기타)는 주화연료(主火燃料)(경유)에 대한 율을 표시한다.",
"- ⑩ 널말뚝 박기 때에는 널말뚝 단면이 내접하여 만들어진 구형 단면의 주장과 동일 주장을 갖는 말뚝의 품으로 한다.",
"- ⑪ 강관 및 콘크리트 말뚝을 디젤해머로 타설하는 경우 「건설공사 표준품셈 공통부문, 8-2-22 디젤 파일 해머(2025)」 항목에 의한다."
],
"notes": [],
"condition_note": [
"관입률 ",
"0.3",
@@ -39906,8 +39829,7 @@
"- ② 조약돌의 크기는 망눈보다 크고 망태지름의 1/2보다 작은 것을 사용한다.",
"- ③ 돌망태의 규격은 KSF 4601에 맞는 것으로써 공장제품을 구입 사용하는 것으로 한다.",
"- ④ 돌망태의 간격가수(間隔加數)는 1연당 0.05m를 기준으로 한 것이다.",
"- ⑤ 필터매트(부직포)를 설치할 경우 특별인부 0.09인/㎡, 보통인부 0.15인/㎡를 적용한다.",
"- 2. 기계"
"- ⑤ 필터매트(부직포)를 설치할 경우 특별인부 0.09인/㎡, 보통인부 0.15인/㎡를 적용한다."
],
"condition_note": [
"지름(㎝) 공종",
@@ -40070,8 +39992,7 @@
"- ② 조약돌의 크기는 망눈보다 크고 망태지름의 1/2보다 작은 것을 사용한다.",
"- ③ 돌망태의 규격은 KSF 4601에 의하고 다른 제품을 사용할 때는 조립설치품을 증감한다.",
"- ④ 돌망태의 간격가수(間隔加數)는 1연당 0.05m를 기준으로 한 것이다.",
"- ⑤ 필터매트(부직포)를 설치할 경우 특별인부 0.09인/㎡, 보통인부 0.15인/㎡를 적용한다.",
"- 2. 기계"
"- ⑤ 필터매트(부직포)를 설치할 경우 특별인부 0.09인/㎡, 보통인부 0.15인/㎡를 적용한다."
],
"condition_note": [
"지름(㎝) 공종",
@@ -40761,12 +40682,7 @@
"special_glyphs": [],
"capacity_formula_here": true,
"variant_key": [],
"notes": [
"[주] ① 목재공작물의 설치에 소요되는 잡재료비는 실소요량을 산출하여 계상한다.",
"- ② 공작물별 구조의 구분과 적용은 다음의 기준을 따른다.",
"- - 간단구조 : 현장 가공이 필요 없는 외부 제작 목구조체의 현장 설치",
"- - 보통구조 : 현장 실정에 맞춰 일부 가공이 필요한 목구조체의 현장 설치"
],
"notes": [],
"condition_note": [
"구 분",
"적 용",
@@ -40830,12 +40746,7 @@
"식생매트설치",
"복 토"
],
"notes": [
"[주] ① 목재공작물의 설치에 소요되는 잡재료비는 실소요량을 산출하여 계상한다.",
"- ② 공작물별 구조의 구분과 적용은 다음의 기준을 따른다.",
"- - 간단구조 : 현장 가공이 필요 없는 외부 제작 목구조체의 현장 설치",
"- - 보통구조 : 현장 실정에 맞춰 일부 가공이 필요한 목구조체의 현장 설치"
],
"notes": [],
"condition_note": [
"구 분",
"규 격",
@@ -41158,12 +41069,7 @@
],
"capacity_formula_here": false,
"variant_key": [],
"notes": [
"[주] ① 인부품에는 횡목준비, 횡목설치, 잔가지 정리 및 되메우기를 포함한다.",
"- ② 횡목 또는 지지목으로 사용하고 남은 산물을 처리하는데 소요되는 시간을 포함한다.",
"- ③ 횡목의 직경은 20 30cm으로 제한한다.",
"- ④ 벌도목(횡목, 지지목, 주변 방해목)의 직경과 가지량에 따라 작업조건을 분류한다."
],
"notes": [],
"condition_note": [
"작업조건",
"벌도목 직경",
@@ -48,6 +48,8 @@ MASTER = OUT_DIR / "work_item_master_2026-01-01.json"
#: ③ 원문 전수 대조 60건 중 **원문 괄호가 분명한 16표**의 밑수를 채움
#: ⚠ 그 가운데 **하나(F0430)만 값이 바뀜** — 원문이 「1일당」인데 「개」로 서 있던 왜곡을 고침
#: ④ 표 아래 `[주]` 글을 `notes` 칸으로 실음(순수 더하기 — 원문 셀·밑수·형태 다 그대로)
#: ⑤ 그 `[주]` 추출의 오염을 걷어냄 — 원문이 절 제목을 목록 줄로 적어 제목·다음 절 [주]까지
#: 끌어오고 있었음(산림 표 320 → 306 · 건설 1,761 → 1,106)
#: ⇒ 곱하면 안 되던 줄이 곱할 수 있게 된 것이지, 있던 값이 바뀐 것이 아니다.
#: 2026-09-17 랩탑 메인 — 목차 오기 둘을 본문 번호로 바로잡아(브레인 지시) **네 줄만** 바뀌어 새로 뜸
#: (옛 f8b8fba1…). 네 줄 모습은 `test_목차_오기는_본문_번호로_바로잡고_열쇠는_그대로` 가 잼 ·
@@ -55,7 +57,7 @@ MASTER = OUT_DIR / "work_item_master_2026-01-01.json"
#: 2026-09-17 랩탑 메인 둘째 — 헛단위 뺌(인용을 제목으로 읽은 13-3 표 셋 · 부록 사례 번호 겹침 일곱)으로 다시 뜸
#: (옛 be88f730…). 바뀐 줄은 13-3·4-1·4-2·2-1·2-2·3-1·3-2·3-3·13-4-1·13-5-2 의 표 귀속뿐 —
#: `test_work_item_master_toc` 가 자리를 잼 · 단가표 대조는 그 파일 머리.
BASELINE_WORK_ITEMS_SHA = "fd11a8e01d33cff46db3096a2827e114ce4af603a0dc85ba0a93f9f477ae9dd9"
BASELINE_WORK_ITEMS_SHA = "5afde1bd7e75db519d7d647f2f254ca7cec9d34a19b945a00502799e8cb718b8"
#: 열쇠 작업이 새로 얹은 칸. 지문을 잴 때만 떼어낸다.
ADDED_FIELDS = (
@@ -373,13 +375,31 @@ def test_표_아래_주석이_실린다(master: dict) -> None:
"""
by_id = {t["pum_table_id"]: t for it in master["work_items"] for t in it["tables"]}
쓰인것 = [t for t in by_id.values() if t.get("notes")]
assert len(쓰인것) == 320
assert len(쓰인것) == 306
발파 = " ".join(by_id["F0245"]["notes"])
assert "인건비의 20%를 가산" in 발파
유로폼 = " ".join(by_id["F0395"]["notes"])
assert "인력품의 3%" in 유로폼
# 남의 [주]를 물어 오지 않는다 — 다음 절을 만나면 멈춘다
assert all(not n.startswith("#") for t in 쓰인것 for n in t["notes"])
# ⚠ **남의 글을 물어 오지 않는다**(2026-09-17 랩탑 서브 전수 확인으로 드러난 오염을 고침)
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Table import (
NOTE_STOP_RE,
trim_page_break,
)
= [n for t in 쓰인것 for n in t["notes"]]
assert all(not n.startswith("#") for n in )
# 원문이 절 제목을 목록 줄로 적는다 — 「- 3. 노상 및 노반재료」·「- 라. 체적환산계수(f)표」
assert not [n for n in if NOTE_STOP_RE.match(n)]
assert NOTE_STOP_RE.match("- 3. 노상 및 노반재료")
assert NOTE_STOP_RE.match("- 라. 체적환산계수(f)표")
assert not NOTE_STOP_RE.match("- ② 장비는 무한궤도 굴착기(0.7㎥)를 적용한다.")
# 쪽이 넘어가며 줄 **끝에** 눌어붙은 쪽번호·장 제목도 뗀다
assert trim_page_break("- ⑥ 적재운반 적하는 1인을 기준으로 한다.15제1장 적용기준") == (
"- ⑥ 적재운반 적하는 1인을 기준으로 한다."
)
# 제 [주] 가 없는 표가 제목 건너 남의 [주] 를 빌려오지 않는다(F0009 는 강재류 것을 빌려왔었다)
by_id2 = {t["pum_table_id"]: t for it in master["work_items"] for t in it["tables"]}
assert not by_id2["F0009"].get("notes")
def test_원문_대조_밑수_판정(master: dict) -> None: