knowledge (구 Aislo-law 독립 저장소 → resources/knowledge 이관, 저장소 폐지): - 법령·행정규칙·표준시방서·교본 원문 + 기술문서 55건 + 실무 분석·종합비교 - 루트 지침 체계: README(지도)·00_운영지침·01_수집지침·02_분석지침· 03_미결_및_확인사항(교본 충돌 리스트 포함)·04_참조_법령기준_목록 - 기술문서 55건 원문 전수 검증 완료 (사방 설계홍수량 법정 기준 등 반영) - 정리: CAD·오피스 잔재 142건, 중복 zip 7건(413MB), 빈 폴더 30개 제거 resources 그룹 재편 (이름순 그룹핑): - app_branding(구 prog_icon.jpg)·app_policies(구 legal)· data_global_contours(구 grobal_contours)·data_rainfall_idf_cache(구 wamis_contours)· template_2dDrawing(구 dwg_analysis/templete — 오타 교정, 상수·경로 동기화) - dwg_analysis(분석 완료 1.8GB)·templates(빈 폴더)·templete_calc_cost.xlsx 삭제 - 참조 코드 5파일 경로 수정 + 프론트 재빌드 (구 경로 잔존 0) - .gitignore: resources 추적 전환, national_contours.gpkg(22GB) 영구 제외 - .env: knowledge 수집용 API 정보 주석 통합 (KCSC·법령센터·조달청 제비율) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
93 lines
3.4 KiB
Python
93 lines
3.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""ASCII 박스표(┌┬┐│├┼┤└┴┘─)를 정식 마크다운 표로 변환.
|
|
|
|
법령 조문의 <img> 안에 있던 박스 드로잉 표가 이미지 로컬화 후 텍스트로 남는데,
|
|
│로 열을 구분하므로 md 표로 복원한다. 각 표에는 대응 ![그림]도 이미 있다.
|
|
"""
|
|
import re, sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
BORDER = set("┌┬┐├┼┤└┴┘─━┏┳┓┣╋┫┗┻┛│┃ \t")
|
|
VBAR = "│┃|"
|
|
QP = re.compile(r"^\s*>+\s?") # 인용블록 접두 '> '
|
|
|
|
def unq(l):
|
|
return QP.sub("", l)
|
|
|
|
def is_border(l):
|
|
s = unq(l).strip()
|
|
return bool(s) and all(c in BORDER for c in s) and any(c in "─━┼┬┴┌┐└┘├┤" for c in s)
|
|
|
|
def is_data(l):
|
|
return any(c in "│┃" for c in unq(l))
|
|
|
|
def split_cells(l):
|
|
s = unq(l).strip().strip("│┃")
|
|
return [c.strip() for c in re.split(r"[│┃]", s)]
|
|
|
|
def convert_block(lines):
|
|
rows = [split_cells(l) for l in lines if is_data(l)]
|
|
rows = [r for r in rows if any(c for c in r)]
|
|
if len(rows) < 2:
|
|
return None
|
|
w = max(len(r) for r in rows)
|
|
if w < 2:
|
|
return None
|
|
rows = [r + [""] * (w - len(r)) for r in rows]
|
|
esc = lambda c: c.replace("|", "\\|")
|
|
out = ["| " + " | ".join(esc(c) for c in rows[0]) + " |",
|
|
"|" + "|".join(["---"] * w) + "|"]
|
|
for r in rows[1:]:
|
|
out.append("| " + " | ".join(esc(c) for c in r) + " |")
|
|
return out
|
|
|
|
def fix(md_path):
|
|
lines = md_path.read_text(encoding="utf-8").split("\n")
|
|
out = []
|
|
i, n = 0, len(lines)
|
|
changed = 0
|
|
infence = False
|
|
while i < n:
|
|
if lines[i].lstrip().startswith("```"):
|
|
infence = not infence
|
|
out.append(lines[i]); i += 1
|
|
continue
|
|
# 박스표 블록 시작: border 또는 data(│ 포함) 연속 (펜스 밖에서만)
|
|
if not infence and (is_border(lines[i]) or (is_data(lines[i]) and not lines[i].lstrip().startswith("|"))):
|
|
j = i
|
|
block = []
|
|
while j < n and (is_border(lines[j]) or (is_data(lines[j]) and not lines[j].lstrip().startswith("|"))):
|
|
block.append(lines[j]); j += 1
|
|
data_rows = [b for b in block if is_data(b)]
|
|
md = convert_block(block)
|
|
# 열이 일정한 진짜 표만 md 표로. 아니면(수식 등) 코드펜스로 정렬 보존.
|
|
widths = {len(split_cells(b)) for b in data_rows}
|
|
if md and len(data_rows) >= 2 and len(widths) == 1:
|
|
out += ["", *md, ""]
|
|
changed += 1
|
|
i = j
|
|
continue
|
|
if len(data_rows) >= 1 or any(is_border(b) for b in block):
|
|
trimmed = [b.rstrip() for b in block if b.strip()]
|
|
if trimmed:
|
|
out += ["", "```text", *trimmed, "```", ""]
|
|
changed += 1
|
|
i = j
|
|
continue
|
|
out.append(lines[i]); i += 1
|
|
if changed:
|
|
md_path.write_text("\n".join(out), encoding="utf-8")
|
|
return changed
|
|
|
|
if __name__ == "__main__":
|
|
total = 0
|
|
for md in ROOT.rglob("*.md"):
|
|
if "임도기술교본" in str(md) or "_pipeline" in str(md):
|
|
continue
|
|
c = fix(md)
|
|
if c:
|
|
total += c
|
|
print(f" {c}개 표 {md.parent.parent.name[:26]}/{md.name}")
|
|
print(f"\n박스표 → md표 변환 {total}개")
|