Merge remote-tracking branch 'origin/sub_desktop_1' into main_desktop_1
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
| 28 변환·수량산출·식언어 | **식 변수의 대상/저장 비목** · 수량산출서 셀별명 · 조달청 변환 · 직종 106종 | (저장소 파일) |
|
||||
| 29 암호화자료의 뼈대 | **값 없이 구조만** — 스키마 평문, 카탈로그 규모, 분류 4~5단, 단위 59~130종 | (저장소 파일) |
|
||||
| 30 조달청 호환규정 XSD | ⭐ **국가 표준 납품 규격 전문** — 문서 뼈대·제경비 적용산식·기계경비 산출 | (저장소 파일) |
|
||||
| 31 일위대가 레시피 사전 | ⭐ **조합 350개 전수** — 누락 감사 포함. 값 없이 조합만 확보 | (저장소 파일) |
|
||||
|
||||
> **정본은 저장소 파일이다** — `resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/`.
|
||||
> 위 Orca 링크는 보기용이며, 문서를 지식DB 자리로 옮기면서 주소가 한 번 바뀌었다.
|
||||
@@ -137,6 +138,9 @@
|
||||
| 식을 데이터로 저장 | 우리 계약 | **규격이 `적용산식`·`적용산식설명`을 요구** | 30번 §3 |
|
||||
| 노임 환산 갈래 | 화면 문자열 | **`H0`~`H5` 규격 코드** (일반·터널·장대터널·준설선 3종) | 30번 §4 |
|
||||
| 손료 산출 | 한 갈래로 봄 | ⚠ **주간/야간/2교대/3교대 네 갈래** — 뽑은 25개는 `E0` 뿐 | 30번 §4 |
|
||||
| **일위대가 조합** | 표준본 암호화라 못 얻는 줄 앎 | ⭐ **실무 조합 350개 확보** — 일위대가 132·단가산출 136·중기 82 | 31번 |
|
||||
| 조합 누락 | — | **일위대가표·중기사용료 0건.** 설명 안 되는 누락 0건 | 31번 §2 |
|
||||
| 규격별 조합 | — | **구성은 같고 수량만 비례** — 한 조합 + 규격별 수량표로 접힘 | 31번 §3.3 |
|
||||
|
||||
분석일: 2026-09-13
|
||||
대상: `C:\경영정보(주)`
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
# 일위대가 레시피 사전 — 어떤 조합인가, 빠진 것은 없는가
|
||||
|
||||
작성일: 2026-09-13
|
||||
목적: **값이 아니라 조합**을 확보하는 것. 표준 일위대가 배포본(`표준일위대가_*.STBSC`)은 암호화라 못 읽지만, **실무에서 실제 쓴 조합**은 출력 엑셀에 평문으로 남는다.
|
||||
산출물: `30_원자료/일위대가_레시피.json` (265.8 KB)
|
||||
재현 스크립트: `40_스크립트/recipe_extract.py`
|
||||
|
||||
## 1. 왜 이것이 값어치가 있나
|
||||
|
||||
```text
|
||||
STmate 표준일위대가(암호화) = 조합 + 값(반기마다 바뀜)
|
||||
우리가 확보한 것 = 조합 350개 ← 임도·사방 실무에서 실제 쓴 것
|
||||
+ 현행 표준품셈 = 값
|
||||
──────────────────────────────────────────────
|
||||
= Aislo 표준일위대가
|
||||
```
|
||||
|
||||
**값은 반기마다 바뀌므로 가질 이유가 없고, 조합은 잘 바뀌지 않는다.** 게다가 이 350개는 범용 카탈로그가 아니라 **임도·사방 설계서 6건에서 실제로 쓰인 것**이라 우리 쪽에 더 맞는다.
|
||||
|
||||
⚠ 수량(`0.08`·`2.09`)은 **그 시점 품셈값**이다. **조합은 그대로 쓰되 수량은 현행 품셈으로 다시 맞춰야 한다.**
|
||||
|
||||
## 2. 누락 감사 — 호표 526개를 하나씩 셌다
|
||||
|
||||
| 시트 | 호표 | 정상 추출 | 중복 | 제목 못 잡음 | 빈 호표 | 못 잡음 |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| 일위대가표 | 170 | **170** | 38 | 0 | 0 | **0** |
|
||||
| 중기사용료 | 143 | **143** | 61 | 0 | 0 | **0** |
|
||||
| 단가산출근거 | 213 | 187 | 51 | 0 | 5 | **21** |
|
||||
| **합계** | **526** | **500** | 150 | 0 | 5 | **21** |
|
||||
|
||||
**일위대가표·중기사용료는 한 개도 안 빠졌다.** 「중복」은 같은 조합이 여러 프로젝트에 나온 것으로, 중복을 걷어내면 **서로 다른 조합 350개**다.
|
||||
|
||||
### 2.1 못 잡은 21개의 정체 — 전부 확인함
|
||||
|
||||
| 갈래 | 예 | 왜 |
|
||||
|---|---|---|
|
||||
| **운반 계산** | `중기운반(현동) L=36.1km` · `기계운반` · `시멘트운반 L=62.5km` | 구성이 자원 목록이 아니라 **거리·속도 인자**(`L1`·`L2`·`V1`~`V4`)로만 이뤄짐 |
|
||||
| **기계+인력 조합 터파기** | `측구터파기(토사) 기계100%` · `구조물터파기 기계90%+인력10%` · `구조물 되메우기` | 기계분과 인력분을 비율로 섞는 꼴이라 한 줄 패턴으로 안 잡힘 |
|
||||
|
||||
**둘 다 값을 못 읽은 것이 아니라 「자원 조합」이 아닌 것이다.** 운반 인자와 기계·인력 비율은 23번 §4(운반 사이클)·26번 §1(`Cm` 54꼴)에서 이미 따로 다뤘다.
|
||||
|
||||
### 2.2 빈 호표 5개
|
||||
|
||||
`무대처리` · `흙 쌓 기` · `사토 무대처리` 등 **합계가 0원인 항목**이다. 내역에는 수량만 잡고 금액이 0인 공종으로, 조합이 없는 것이 정상이다.
|
||||
|
||||
⇒ **설명되지 않는 누락은 0건이다.**
|
||||
|
||||
## 3. 확보한 조합 350개
|
||||
|
||||
| 종류 | 개수 | 무엇 |
|
||||
|---|---:|---|
|
||||
| **일위대가** | **132** | 자원·하위 호표를 조합해 공종 단가를 만듦 |
|
||||
| **단가산출** | **136** | 기계 `Q`식으로 시간당 사용료를 작업량으로 나눔 |
|
||||
| **중기** | **82** | 손료 + 운전원 + 연료 + 잡품 |
|
||||
| 구성행 | 1,729 | 조합당 평균 **4.9개** |
|
||||
| `Q`식을 가진 것 | **107** | |
|
||||
|
||||
### 3.1 구성 개수 분포
|
||||
|
||||
```text
|
||||
1개 11 · 2개 14 · 3개 17 · 4개 90 · 5개 29 · 6개 14 · 7개 15
|
||||
8개 10 · 9개 5 · 10개 3 · 11개 3 · 12개 1 · 13개 1 · 17개 1
|
||||
```
|
||||
|
||||
**4개짜리가 90개로 최다** — 중기 호표(손료·운전원·연료·잡품)가 그 꼴이다.
|
||||
|
||||
### 3.2 ⭐ 150 / 350 이 다른 호표를 참조한다
|
||||
|
||||
조합이 **2단 이상으로 쌓인다.** 17번 §5의 위상순서 계산이 여기서도 확인된다.
|
||||
|
||||
```text
|
||||
기슭막이(깬잡석,찰쌓기 L3=45m) H=2.0m / M ← 9개 구성
|
||||
깬잡석채집 L=45cm 내외 M2 2.09
|
||||
깬잡석찰쌓기 L3=45cm내외 M2 2.09 ← 다른 호표
|
||||
고임돌채집 기계(0.7㎥,100%) M3 0.31
|
||||
막자갈채집 기계(0.7㎥,100%) M3 0.48
|
||||
기초다짐 및 뒤채움 소형 장비사용 시공 M3 0.48
|
||||
PVC파이프 VG1(50m/m) M 0.94
|
||||
유로폼 설치 및 해체 간단 m2 0.85
|
||||
레미콘타설(장비) 무근 m3 0.31
|
||||
콘크리트믹서사용 0.45 m3 m3 0.42
|
||||
|
||||
└ 깬잡석찰쌓기 L3=45cm내외 / M2 ← 3개 구성
|
||||
석공 인 0.08
|
||||
보통인부 인 0.04
|
||||
굴삭기(타이어) 0.6㎥,(부착용집게) 시간 0.30
|
||||
```
|
||||
|
||||
### 3.3 ⭐ 규격이 바뀌면 수량만 비례한다
|
||||
|
||||
```text
|
||||
기슭막이 … H=2.0m 깬잡석채집 2.09 · 고임돌 0.31 · 막자갈 0.48 · PVC 0.94
|
||||
기슭막이 … H=2.5m 깬잡석채집 2.61 · 고임돌 0.39 · 막자갈 0.79 · PVC 1.28
|
||||
```
|
||||
|
||||
**구성 목록은 같고 수량만 높이에 따라 달라진다.** 규격별로 조합을 새로 만들 필요 없이 **한 조합 + 규격별 수량표**로 둘 수 있다는 뜻이다.
|
||||
|
||||
### 3.4 가장 많이 쓰인 구성 자원
|
||||
|
||||
| 자원 | 단위 | 등장 조합 수 | | 자원 | 단위 | 등장 |
|
||||
|---|---|---:|---|---|---|---:|
|
||||
| 잡품 | % | **70** | | 화물차운전사 | 인 | 15 |
|
||||
| 경유 | L | **68** | | 굴삭기(무한궤도) | 천원 | 13 |
|
||||
| 건설기계운전사 | 인 | **52** | | 면목 | M | 13 |
|
||||
| 보통인부 | 인 | **43** | | 콘크리트비빔 | m3 | 12 |
|
||||
| 유로폼 설치 및 해체 | m2 | 24 | | 철근가공 및 조립 | ton | 11 |
|
||||
| 석공 | 인 | 23 | | 덤프트럭 | 천원 | 11 |
|
||||
| **건설표준품셈** | — | **23** | | 레미콘 | M3 | 11 |
|
||||
| 고임돌채집 | m3 | 21 | | 기초잡석채집및운반부설 | M3 | 11 |
|
||||
| 레미콘타설(장비) | m3 | 19 | | 막자갈채집 | m3 | 11 |
|
||||
|
||||
⇒ **`건설표준품셈`이 23개 조합에 근거로 적혀 있다.** 어느 품셈 조항에서 왔는지가 텍스트로 남는다(`▣ 토공의 비탈규준틀[개소]2-6-1` 같은 꼴). 현행 품셈으로 갱신할 때 **대조점이 된다.**
|
||||
|
||||
`잡품`이 70개 조합에 나오는 것은 중기 호표마다 붙기 때문이고, **수량×단가가 아니라 연료비에 비율을 곱하는 가산 행**이다(17번 §3).
|
||||
|
||||
## 4. 산출물 구조
|
||||
|
||||
`30_원자료/일위대가_레시피.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"종류": "일위대가",
|
||||
"명칭": "깬잡석찰쌓기",
|
||||
"규격": "L3=45cm내외",
|
||||
"단위": "M2",
|
||||
"Q식": null,
|
||||
"품셈근거": null,
|
||||
"구성": [
|
||||
{"명칭": "석공", "규격": "", "단위": "인", "수량": 0.08},
|
||||
{"명칭": "보통인부", "규격": "", "단위": "인", "수량": 0.04},
|
||||
{"명칭": "굴삭기(타이어)", "규격": "0.6㎥,(부착용집게)", "단위": "시간", "수량": 0.3}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
단가산출 계열은 `Q식`(예: `3600*q*K*f*E/Cm`)과 `품셈근거`가 함께 담긴다.
|
||||
|
||||
## 5. 이대로 쓰려면 해야 할 것
|
||||
|
||||
1. **수량을 현행 표준품셈으로 갱신** — 조합은 그대로, 수량만. `품셈근거` 문자열이 대조점이다.
|
||||
2. **자원 이름을 우리 코드에 잇기** — `30_원자료/stmate_code_name_list.csv`(894개)와 짝지어 쓴다.
|
||||
3. **못 잡은 21개 보완** — 운반 계산과 기계·인력 비율 조합은 **별도 꼴**로 다뤄야 한다(26번 §1의 `Cm` 식, 23번 §4의 운반 사이클 참조).
|
||||
4. **규격별 수량표로 접기** — §3.3처럼 같은 조합이 규격만 다른 것이 많다.
|
||||
|
||||
## 6. 한 줄 정리
|
||||
|
||||
| 물음 | 답 |
|
||||
|---|---|
|
||||
| 어떤 조합인가 | **350개** — 일위대가 132 · 단가산출 136 · 중기 82. 구성행 1,729 |
|
||||
| 빠진 것은 없나 | **일위대가표·중기사용료 0건 누락.** 단가산출 21개는 「자원 조합이 아닌 것」(운반 인자·기계인력 비율)이고 5개는 금액 0인 빈 호표. **설명 안 되는 누락 0건** |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
### 누락 감사 — 출력 엑셀 6개
|
||||
종류 호표 정상 중복 제목없음 빈호표 구성없음
|
||||
일위대가 170 170 38 0 0 0
|
||||
중기 143 143 61 0 0 0
|
||||
단가산출 213 187 51 0 5 21
|
||||
|
||||
호표 526개 중 500개 처리 (95.1%) · 못 잡은 것 26개
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표14 측구터파기(토사) 기계100%(굴삭기 0.4 줄67
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표21 구조물터파기(육상토사0~1m) 기계90%+인 줄66
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표23 구조물터파기(육상토사0~1m) 기계100%( 줄32
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표24 구조물 되메우기 기계100%(굴삭기 0.7M 줄32
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표59 중기운반(현동) L=36.1km 줄68
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표60 기계운반(현동) L=36.1km 줄33
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표61 시멘트운반(현동) L=62.5km 줄66
|
||||
2024년 산불진화임도 실시설계( 단가산출근거 호표64 철근운반(현동) L=62.5km 줄31
|
||||
2024년 간선임도사업(기번3) 단가산출근거 호표21 중기운반(울진군 울진읍 대흥리) L=19.0 줄68
|
||||
2024년 간선임도사업(기번3) 단가산출근거 호표24 시멘트운반(울진군 울진읍 대흥리) L=19. 줄66
|
||||
|
||||
### 서로 다른 조합 350개
|
||||
단가산출 136개
|
||||
일위대가 132개
|
||||
중기 82개
|
||||
구성행 합계 1729 (조합당 평균 4.9)
|
||||
Q식을 가진 조합 107개
|
||||
|
||||
→ 일위대가_레시피.json 265.8 KB
|
||||
@@ -0,0 +1,125 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""일위대가 레시피 사전 — 전수 추출 + 누락 감사.
|
||||
시트 셋(일위대가표·중기사용료·단가산출근거)의 호표를 하나도 빠뜨리지 않는다."""
|
||||
import sys, io, re, pathlib, warnings, collections, json
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
|
||||
warnings.filterwarnings("ignore"); import openpyxl
|
||||
|
||||
def _repo():
|
||||
p = pathlib.Path(__file__).resolve()
|
||||
for q in p.parents:
|
||||
if (q / "resources" / "knowledge").is_dir(): return q
|
||||
return pathlib.Path(r"D:\aislo-wt\sub")
|
||||
REPO = _repo(); PRAC = REPO / "resources" / "knowledge" / "original" / "실무문서"
|
||||
|
||||
HOPYO = re.compile(r"^제?\s*\d+\s*호표$")
|
||||
RE_COMP = re.compile(r"(노\s*무\s*비|재\s*료\s*비|경\s*비)\s*:\s*([\d,]+(?:\.\d+)?)\s*/\s*Q")
|
||||
RE_QF = re.compile(r"\bQ\s*=\s*([^=\n']{3,70})")
|
||||
RE_DIRECT = re.compile(r"^\s*([^:*=]{2,40}?)\s*:\s*([\d,]+(?:\.\d+)?)\s*\*\s*([\d,]+(?:\.\d+)?)\s*([^\s/=]{0,8})")
|
||||
RE_PUM = re.compile(r"[▣▶●]\s*(.{3,60})")
|
||||
RE_REV = re.compile(r"^\s*([\d,]+(?:\.\d+)?)\s*\*\s*([\d,]+(?:\.\d+)?)\s*=")
|
||||
SKIP = {"합계", "계", "소계", "총계", "총합계"}
|
||||
|
||||
def parse_grid(ws):
|
||||
"""일위대가표·중기사용료 — A열 제목, 구성이 자원행."""
|
||||
rows = [list(r) for r in ws.iter_rows(min_row=1, max_row=ws.max_row, max_col=14, values_only=True)]
|
||||
out = []; cur = None
|
||||
for r in rows:
|
||||
a = (str(r[0]) if r[0] is not None else "").strip()
|
||||
k = a.replace(" ", "")
|
||||
if HOPYO.match(k):
|
||||
cur = {"no": len(out)+1, "title": None, "items": [], "q": None, "raw": 0}; out.append(cur); continue
|
||||
if cur is None: continue
|
||||
if k in SKIP: continue
|
||||
cur["raw"] += 1
|
||||
if cur["title"] is None and a and (r[3] not in (None, "")) and (r[2] in (None, "")):
|
||||
cur["title"] = (a, str(r[1] or "").strip(), str(r[3] or "").strip()); continue
|
||||
if a and (r[2] not in (None, "")):
|
||||
cur["items"].append((a, str(r[1] or "").strip(), str(r[3] or "").strip(), r[2]))
|
||||
return out
|
||||
|
||||
def parse_san(ws):
|
||||
"""단가산출근거 — B열 제목('명칭 규격 / 단위'), 구성은 산식(중기 시간당단가 / Q)."""
|
||||
rows = [list(r) for r in ws.iter_rows(min_row=1, max_row=ws.max_row, max_col=8, values_only=True)]
|
||||
out = []; cur = None
|
||||
for r in rows:
|
||||
b = (str(r[1]) if r[1] is not None else "").strip()
|
||||
k = b.replace(" ", "")
|
||||
if HOPYO.match(k):
|
||||
amt = sum(x for x in r[2:6] if isinstance(x,(int,float)))
|
||||
cur = {"no": len(out)+1, "title": None, "items": [], "q": None, "pum": None, "raw": 0, "amt": amt}; out.append(cur); continue
|
||||
if cur is None: continue
|
||||
if k in SKIP: continue
|
||||
cur["raw"] += 1
|
||||
if cur["title"] is None and b and "/" in b:
|
||||
nm, _, un = b.rpartition("/")
|
||||
nm = nm.strip(); un = un.strip(); sz = ""
|
||||
if " " in nm:
|
||||
p1, p2 = nm.split(" ", 1); nm, sz = p1.strip(), p2.strip()
|
||||
cur["title"] = (nm, sz, un); continue
|
||||
m = RE_QF.search(b)
|
||||
if m and cur["q"] is None: cur["q"] = re.sub(r"\s+", "", m.group(1))
|
||||
hit = False
|
||||
for mm in RE_COMP.finditer(b):
|
||||
cur["items"].append((mm.group(1).replace(" ", ""), "시간당 성분단가", "원", mm.group(2))); hit = True
|
||||
if not hit:
|
||||
md = RE_DIRECT.match(b)
|
||||
if md:
|
||||
cur["items"].append((md.group(1).strip(), "", md.group(4).strip(), md.group(3)))
|
||||
hit = True
|
||||
if not hit:
|
||||
mr = RE_REV.match(b)
|
||||
if mr:
|
||||
cur["items"].append(((str(r[0]) if r[0] is not None else "").strip() or "자원", "", "", mr.group(1)))
|
||||
hit = True
|
||||
if not hit and cur.get("pum") is None:
|
||||
mp = RE_PUM.search(b)
|
||||
if mp: cur["pum"] = mp.group(1).strip()
|
||||
return out
|
||||
|
||||
SHEETS = {"일위대가표": "일위대가", "중기사용료": "중기", "단가산출근거": "단가산출"}
|
||||
rec = {}; audit = collections.Counter(); miss = []; files = 0
|
||||
for p in sorted(PRAC.rglob("*.xlsx")):
|
||||
if p.name.startswith("~$"): continue
|
||||
try: wb = openpyxl.load_workbook(p, data_only=True, read_only=True)
|
||||
except Exception: continue
|
||||
if "공사원가계산서" not in wb.sheetnames: continue
|
||||
files += 1
|
||||
for sh, kind in SHEETS.items():
|
||||
if sh not in wb.sheetnames: continue
|
||||
bs = parse_san(wb[sh]) if sh == "단가산출근거" else parse_grid(wb[sh])
|
||||
audit[(kind, "호표")] += len(bs)
|
||||
for b in bs:
|
||||
if not b["title"]:
|
||||
audit[(kind, "제목없음")] += 1; miss.append((p.stem[:18], sh, b["no"], "제목 못 잡음", b["raw"])); continue
|
||||
if not b["items"]:
|
||||
if not b.get("amt"): audit[(kind, "빈호표")] += 1
|
||||
else: audit[(kind, "구성없음")] += 1; miss.append((p.stem[:18], sh, b["no"], b["title"][0][:24], b["raw"]))
|
||||
continue
|
||||
audit[(kind, "정상")] += 1
|
||||
key = (kind,) + b["title"]
|
||||
if key in rec: audit[(kind, "중복")] += 1
|
||||
else: rec[key] = (b["items"], b["q"], b.get("pum"))
|
||||
|
||||
print("### 누락 감사 — 출력 엑셀 %d개" % files)
|
||||
print("%-10s %7s %7s %7s %8s %8s %8s" % ("종류","호표","정상","중복","제목없음","빈호표","구성없음"))
|
||||
for kind in ("일위대가", "중기", "단가산출"):
|
||||
print("%-10s %7d %7d %7d %8d %8d %8d" % (kind, audit[(kind,"호표")], audit[(kind,"정상")],
|
||||
audit[(kind,"중복")], audit[(kind,"제목없음")], audit[(kind,"빈호표")], audit[(kind,"구성없음")]))
|
||||
tot = sum(audit[(k,"호표")] for k in SHEETS.values()); ok = sum(audit[(k,"정상")] for k in SHEETS.values())
|
||||
print("\n 호표 %d개 중 %d개 처리 (%.1f%%) · 못 잡은 것 %d개" % (tot, ok, 100*ok/tot, tot-ok))
|
||||
for m in miss[:10]: print(" %-18s %-12s 호표%-4d %-26s 줄%d" % m)
|
||||
|
||||
print("\n### 서로 다른 조합 %d개" % len(rec))
|
||||
for a, b2 in sorted(collections.Counter(x[0] for x in rec).items()): print(" %-10s %3d개" % (a, b2))
|
||||
tot2 = sum(len(v[0]) for v in rec.values())
|
||||
print(" 구성행 합계 %d (조합당 평균 %.1f)" % (tot2, tot2/max(len(rec),1)))
|
||||
nq = sum(1 for v in rec.values() if v[1])
|
||||
print(" Q식을 가진 조합 %d개" % nq)
|
||||
|
||||
out = REPO/"resources"/"knowledge"/"original"/"경쟁사 프로그램"/"STmate 분석"/"30_원자료"/"일위대가_레시피.json"
|
||||
J = [{"종류":k[0], "명칭":k[1], "규격":k[2], "단위":k[3], "Q식":v[1], "품셈근거":(v[2] if len(v)>2 else None),
|
||||
"구성":[{"명칭":a, "규격":c, "단위":u, "수량":(float(q) if isinstance(q,(int,float)) else str(q))}
|
||||
for a,c,u,q in v[0]]} for k,v in sorted(rec.items())]
|
||||
out.write_text(json.dumps(J, ensure_ascii=False, indent=1), encoding="utf-8")
|
||||
print("\n → %s %.1f KB" % (out.name, out.stat().st_size/1024))
|
||||
@@ -69,6 +69,7 @@
|
||||
| 28 | **변환·수량산출·식언어** — 식 변수 대상/저장, 조달청 변환, 직종 106종 |
|
||||
| 29 | **암호화자료의 뼈대** — 값 없이 구조만, 카탈로그 규모와 분류 깊이 |
|
||||
| 30 | ⭐ **조달청 호환규정 XSD** — 국가 표준 납품 규격 전문 |
|
||||
| 31 | ⭐ **일위대가 레시피 사전** — 조합 350개, 누락 감사 |
|
||||
|
||||
## 확정된 굵직한 것
|
||||
|
||||
|
||||
Reference in New Issue
Block a user