import re import sys import json from pathlib import Path sys.stdout.reconfigure(encoding='utf-8') md_path = Path("resources/knowledge/original/행정규칙/임도 품셈 적용기준 (현 산림사업 표준품셈)/첨부/(산림청고시 제2025-82호) 산림사업 표준품셈.md") with open(md_path, "r", encoding="utf-8") as f: lines = f.readlines() # 1. Parse Chapters and Sections # Track current chapter, section, and text before tables chapters = [] for idx, line in enumerate(lines): m = re.match(r'^(#{1,3})\s*(제\s*\d+\s*장(?:\s+[^\,\n]+)?)$', line.strip()) if m and not any(k in line for k in ['참조', '적용기준,', '토질,']): chapters.append((idx + 1, m.group(2).strip())) def get_chapter(line_no): cur_ch = "제0장 머리말" for lno, ch in chapters: if line_no >= lno: cur_ch = ch else: break return cur_ch # 2. Extract tables and their contexts tables = [] current_table = [] start_line = -1 for idx, line in enumerate(lines): line_str = line.strip() if line_str.startswith('|') and line_str.endswith('|'): if not current_table: start_line = idx + 1 current_table.append((idx + 1, line)) else: if current_table: has_sep = any(re.match(r'^\|(?:\s*:?-+:?\s*\|)+$', l.strip()) for _, l in current_table) if has_sep: tables.append({ 'start_line': start_line, 'end_line': current_table[-1][0], 'lines': [l for _, l in current_table] }) current_table = [] if current_table: has_sep = any(re.match(r'^\|(?:\s*:?-+:?\s*\|)+$', l.strip()) for _, l in current_table) if has_sep: tables.append({ 'start_line': start_line, 'end_line': current_table[-1][0], 'lines': [l for _, l in current_table] }) print(f"Extracted {len(tables)} tables.") # Enrich each table with pre-context (up to 15 lines before) and post-context ([주] up to next table/heading) for i, t in enumerate(tables): t_id = f"F{i+1:04d}" t['table_id'] = t_id t['chapter'] = get_chapter(t['start_line']) # Pre-context: lines before start_line pre_start = max(0, t['start_line'] - 15) pre_lines = [lines[j].strip() for j in range(pre_start, t['start_line'] - 1) if lines[j].strip()] t['pre_context'] = pre_lines # Find section title from pre-lines (looking backwards) section = "미식별" for pl in reversed(pre_lines): if re.match(r'^(?:#{1,4}\s*)?(?:\d+[-\.]\d+|\d+\.)', pl): section = pl break t['section'] = section # Post-context: lines after end_line until next table start or heading post_end = len(lines) if i + 1 < len(tables): post_end = min(tables[i+1]['start_line'] - 1, t['end_line'] + 30) else: post_end = min(len(lines), t['end_line'] + 30) post_lines = [] notes = [] in_note = False for j in range(t['end_line'], post_end): lj = lines[j].strip() if not lj: if in_note and len(notes) > 5 and not lj: # allow blank lines inside note pass continue if lj.startswith('#') or (lj.startswith('|') and lj.endswith('|')): break post_lines.append(lj) if '[주]' in lj or '【주】' in lj or re.match(r'^\s*주\s*[:\)]', lj): in_note = True if in_note: notes.append(lj) # if line looks like next section heading, stop if re.match(r'^\d+\s*[\.-]\s*\d+', lj) and not re.match(r'^\s*[\(\[\d]+\s*[\.\)]', lj): break t['post_lines'] = post_lines t['notes'] = notes print(f"Sample table 10 (F0010):") t10 = tables[9] print(f" ID: {t10['table_id']}, Chapter: {t10['chapter']}, Section: {t10['section']}") print(f" Start line: {t10['start_line']}, End line: {t10['end_line']}") print(f" Pre-context (last 3): {t10['pre_context'][-3:]}") print(f" Notes count: {len(t10['notes'])}") if t10['notes']: print(f" Notes sample: {t10['notes'][:3]}")