Files
Aislo/resources/master_data/scripts/_계수_공통2장.py
T
eomsangdonandClaude Sonnet 5 c636ad6a87 feat(master_data): 산림 1장 계수 표 추가 · 건설 공통 2장 3장 소요량 옮김
- 계수_산림품셈_01장: 1-1 · 1-2 · 1-6 · 1-7 표 10개 + 글 속 계수 표 13개 추가 (1-3 · 1-4 그대로)
- 소요량_건설품셈_공통2장: 표 112개(계수 58개 포함)
- 소요량_건설품셈_공통3장: 표 100개(계수 34개 포함)
- 옮기는 스크립트 남김 · 틀 · 본문 검사 0건

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
2026-09-19 16:55:43 +09:00

150 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""건설품셈 공통 제2장 — 글 속 계산용 수(할증률·한도·손율 기준·식 상수 …)를 본문 md 줄에서 뽑아 계수 표로.
build_소요량_건설품셈_공통2장.py 가 부름. 값은 아래 찾을 식으로 md 글에서 읽음(손으로 적지 않음).
"""
import re
CIRC = "①②③④⑤⑥⑦⑧⑨⑩⑪⑫"
# ── 글 속 계수 — (구분, 찾을 식, 단위, 종류) · 종류 n=수 · r=범위(두 수) · x=식 글자 그대로(+원문) ─────────────
TOOL = r"공구손료 및 경장비\(.*?\)의 기계경비는 인력품[의이] (\d+)%로 계상한다"
# fmt: off
LIFT_TEXT = r"""
2-1-2|시멘트 창고 면적식 계수(A=0.4×N/n)|A=(0\.4)×N||n
2-1-2|시멘트 쌓기 단수 최고|쌓기 단수\(최고 (\d+)포대\)|포대|n
2-1-2|시멘트 창고 전량 저장 기준 시멘트량|시멘트량이 (\d+)포대 이내|포대|n
2-1-2|시멘트량 기준 이상일 때 저장 비율(전량 대비)|전량의 (1/3)||x
2-1-2|동력소 및 변전소 면적식 계수(A=3.3√W)|A=(3\.3)√W||n
2-1-2|건설기계 주기장 실제 대당 소요면적 배율|소요면적의 (1\.2)배|배|n
2-1-2|건설기계 주기장 면적 비율(최대 소요면적 기준)|소요면적의 (70)%|%|n
2-1-2|가설전등 등당 전력|등당 (100)W|W|n
2-2-2|철물·강재류 길이 한도(이하)|길이가 (2)m 이하|m|n
2-2-2|철물·강재류 길이 한도 이하 1회 사용 후 손율|손율은 (100)%로 계상|%|n
2-2-2|강재 절단 안 함 손료식의 상수(1+재료의 할증률)|\((1)\+재료의 할증률\)||n
2-2-5|강재비계 내구년한|내구년한 (5\.5)년|년|n
2-4-1|지주간격|지주간격 (2\.0)m|m|n
2-4-2|지주간격|지주간격 (2\.0)m|m|n
2-5-1|규준틀 높이|높이 (0\.5)m|m|n
2-5-2|규준틀 높이|높이 (2\.4)m|m|n
2-6-1|설치높이 한도|설치높이 (4\.2)m까지|m|n
2-6-1|잡재료 및 소모재료율(주재료비 기준)|주재료비의 (5)%|%|n
2-6-2|설치높이 한도|설치높이 (4\.2)m까지|m|n
2-6-2|잡재료 및 소모재료율(주재료비 기준)|주재료비의 (5)%|%|n
2-6-5|설치높이 한도|설치높이 (5)m이하|m|n
2-7-1|비계주위 보호망 미시공 시 시공량 증가율|본 시공량의 (8)%를 증하여|%|n
2-7-1|비계 높이 한도(초과 시 별도 계상)|높이 (30)m 초과|m|n
2-7-2|비계주위 보호망 미시공 시 시공량 증가율|본 시공량의 (8)%를 증하여|%|n
2-7-2|비계 높이 한도(초과 시 별도 계상)|높이 (30)m 초과|m|n
2-7-3|비계주위 보호망 미시공 시 시공량 증가율|본 시공량의 (8)%를 증하여|%|n
2-7-3|비계 높이 한도(초과 시 별도 계상)|높이 (30)m 초과|m|n
2-7-4|비계 높이 한도(초과 시 별도 계상)|높이 (20)m 초과|m|n
2-7-5|수평비계 높이 한도|높이 (10)m이하|m|n
2-7-7|가설계단 높이 한도|높이 (6)m이하에서|m|n
2-7-7|강관 외경|φ (48\.6)㎜|㎜|n
2-7-7|가설계단 폭 한도|폭은 (0\.9)m이하|m|n
2-7-8|가설계단 폭 한도|폭은 (0\.9)m이하|m|n
2-8-1|낙하물방지망 수평방향 한도|수평방향 (3)m이하|m|n
2-8-1|그물망 손율(1회사용 후)|손율은 1회사용 후 (100)%|%|n
2-8-2|낙하물방지망 수평방향 한도|수평방향 (3)m이하|m|n
2-8-2|그물망 손율(1회사용 후)|손율은 1회사용 후 (100)%|%|n
2-8-3|낙하물방지망 수평방향 한도|수평방향 (4)m이하|m|n
2-8-7|그물망 손율(1회 사용 후)|손율은 1회 사용 후 (100)%|%|n
2-8-8|보호망 손율(1회사용 후)|손율은 1회사용 후 (100)%|%|n
2-8-9|보호망 손율(1회사용 후)|손율은 1회사용 후 (100)%|%|n
2-8-12|난간대 길이 한도|길이 (2\.5)m이하|m|n
2-8-14|난간틀 높이 한도|높이 (1\.4)m이하|m|n
2-8-14|난간틀 길이 한도|길이 (1\.3)m이하|m|n
2-8-15|추락방호망 규격(면적, 이하)|규격은 (\d+)~(\d+)㎡이하|㎡|r
2-9-1|울타리 높이|울타리 높이 (2\.0)m|m|n
2-9-2|건설용리프트 규격(싱글)|싱글 (1\.2)ton|ton|n
2-9-3|통로 높이 한도|높이 (3\.0)m이하|m|n
2-9-3|통로 폭|폭 (2\.0)m 기준|m|n
2-9-8|PE가설휀스 길이|L(1\.5)xH|m|n
2-9-8|PE가설휀스 높이|xH(0\.9)m|m|n
2-9-9|가림막 가설휀스 길이|L(2\.0)xH|m|n
2-9-9|가림막 가설휀스 높이|xH(\d\.\d)~(\d\.\d)m|m|r
2-10-1|보호막 손율(1회사용 후)|손율은 1회사용 후 (100)%|%|n
2-10-2|방진망 손율(1회사용 후)|손율은 1회사용 후 (100)%|%|n
2-10-3|터널방음문 차로 한도(이하)|\((3)차로 이하\)|차로|n
2-10-4|간이흙막이 개당 길이 한도|길이는 (3\.0)m 이하|m|n
2-10-4|간이흙막이 폭 한도|폭은 (2\.0)m이하|m|n
2-10-7|방호벽 간격|간격 (2)m|m|n
2-11-1|보양재 손율|손율은 (100)%를 적용|%|n
2-11-5|살수두께|살수두께는 (1\.5)㎜/회|㎜/회|n
2-11-5|살수폭|살수폭은 (4\.0)m|m|n
2-11-5|살수면적 계산 예 - 폭|= (6)m ×|m|n
2-11-5|살수면적 계산 예 - 길이|× (100)m ×|m|n
2-11-5|살수면적 계산 예 - 1일 살수 횟수|× (5)회/일|회/일|n
2-11-5|살수면적 계산 예 - 살수 일수|× (10)일|일|n
2-11-5|살수면적 계산 예 - 살수면적|= (30,000)㎡|㎡|n
2-11-7|슬러지함 규격|슬러지함 (2\.0×1\.2×1\.2)m|m|x
2-12-1|건설용리프트 규격(싱글)|싱글 (1\.2)ton|ton|n
2-12-2|건설용리프트 규격(싱글)|싱글 (1\.2)ton|ton|n
2-12-2|가산 기준 층(이상)|(19)층 이상|층|n
2-12-2|가산 층 간격|매 (3)층 증가마다|층|n
2-12-2|층 간격마다 가산율|증가마다 (4)%씩|%|n
2-12-2|층고 기준(층수 환산)|층고를 (3\.6)m로|m|n
2-12-4|강관장 기준|강관장 (6\.0)m|m|n
"""
# fmt: on
LIFT: dict[str, list] = {}
for _ln in LIFT_TEXT.strip().splitlines():
_it, *_e = _ln.split("|")
LIFT.setdefault(_it, []).append(tuple(_e))
def lift_table(item, title, unesc, N, book):
"""그 항 본문 줄에서 계수 표를 만듦(값은 md 글에서 뽑음). 없으면 None."""
text = [re.sub(r"\s*<br>\s*", " ", unesc(ln)) for ln in item["lines"]]
found = [] # (줄 번호, 차례, 행, 출처 표시)
specs = [("공구손료 및 경장비 기계경비(인력품 기준)", TOOL, "%", "n", True)] + [
(*e, False) for e in LIFT.get(item["id"], [])
]
for seq, (name, rx, unit, kind, many) in enumerate(specs):
hits = [(k, re.search(rx, ln)) for k, ln in enumerate(text) if re.search(rx, ln)]
if not hits:
if many:
continue
raise ValueError(f"글에서 못 찾음 {item['id']} {name} {rx}")
if len(hits) > 1:
raise ValueError(f"여럿 찾음 {item['id']} {name} {rx}")
k, m = hits[0]
row = {"구분": name}
row["값"] = (
[N(m.group(1)), N(m.group(2))]
if kind == "r"
else (m.group(1) if kind == "x" else N(m.group(1)))
)
if kind == "x":
row["값원문"] = m.group(0)
if unit:
row["단위"] = unit
ln = text[k]
if ln.startswith("|"):
ref = "표"
elif ln.startswith("※"):
ref = "※"
elif ln.startswith(">"):
ref = "예시"
else:
back = next((text[b][0] for b in range(k, -1, -1) if text[b][:1] in CIRC), "")
ref = "주" + back
found.append((k, seq, row, ref))
if not found:
return None
found.sort(key=lambda x: x[:2])
refs = list(dict.fromkeys(f[3] for f in found))
return {
"열쇠": f"{item['id']} 계수",
"이름": f"{title} - 글 속 계수",
"기준": "",
"출처": f"{book} {item['id']} " + "·".join(refs),
"그룹": "계수",
"조건": {"구분": "고르기"},
"값칸": {"값": "구분 따름", "단위": "글"},
"줄": [f[2] for f in found],
"주": [],
}