118 lines
4.1 KiB
Python
118 lines
4.1 KiB
Python
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]}")
|