import sys, os, re, json sys.stdout.reconfigure(encoding='utf-8') # 1. Load official TOC items from const master with open('resources/data_work_item_master/const_work_item_master_2026-01-01.json', 'r', encoding='utf-8') as f: master = json.load(f) toc_items = master.get('work_items', []) print(f"Loaded official TOC work items: {len(toc_items)}") # Create a lookup map: (toc_number, division) -> name # Note: number in const is like "1-2-2", "3-3-6", etc. toc_dict = {} for item in toc_items: num = item.get('number', '').strip() name = item.get('name', '').strip() div = item.get('division', '').strip() if num and name and '-' in num: # Key by (division, num) toc_dict[(div, num)] = name # Also key by num alone if num not in toc_dict: toc_dict[num] = [] if isinstance(toc_dict[num], list): toc_dict[num].append((div, name)) print(f"Unique TOC numbers with hyphens: {len([k for k in toc_dict.keys() if isinstance(k, str)])}") base_dir = "resources/knowledge/original/원가계산/건설공사_표준품셈" # Division mapper from file path def get_division(rel_path): if "01_공통부문" in rel_path: return "공통부문" if "02_토목부문" in rel_path: return "토목부문" if "03_건축부문" in rel_path: return "건축부문" if "04_기계설비부문" in rel_path: return "기계설비부문" if "05_유지관리부문" in rel_path: return "유지관리부문" return "" all_md_files = [] for root, dirs, files in os.walk(base_dir): for f in files: if f.endswith('.md') and not f.startswith('_') and '개정사항' not in f and '2026년_건설공사_표준품셈.md' not in f: all_md_files.append(os.path.join(root, f)) verified_fixes = [] for fpath in sorted(all_md_files): rel_path = os.path.relpath(fpath, base_dir) div = get_division(rel_path) with open(fpath, 'r', encoding='utf-8') as f: text = f.read() lines = text.split('\n') file_fixes = [] for line_idx, line in enumerate(lines): line_num = line_idx + 1 if line.strip().startswith('|') and line.strip().endswith('|'): continue # Match pattern: text ending with non-space immediately followed by sec_num # e.g. "한다.1-2-2 단위표준" # We search for any number like \d+-\d+(?:-\d+)? matches = list(re.finditer(r'([^\s#\-\*\>\|])(\d+-\d+(?:-\d+)?)\s*([가-힣\w\(\)\/·\s]*)', line)) for m in matches: prev_char = m.group(1) sec_num = m.group(2) following_text = m.group(3).strip() # check if prev_char is an opening quote or bracket if prev_char in ["'", '"', '‘', '’', '[', '(', '제', '표', '·', ':', '―', '-', '/']: continue # Check against TOC matched_toc = None if (div, sec_num) in toc_dict: matched_toc = toc_dict[(div, sec_num)] elif sec_num in toc_dict and isinstance(toc_dict[sec_num], list): # find match for d, nm in toc_dict[sec_num]: if d == div: matched_toc = nm break if not matched_toc and len(toc_dict[sec_num]) == 1: matched_toc = toc_dict[sec_num][0][1] if matched_toc: # verify following text contains keywords of toc title # e.g. following_text has first word of matched_toc first_word = re.split(r'[\s\(\)]', matched_toc)[0] if first_word and first_word in following_text[:30]: file_fixes.append({ "file": rel_path, "line": line_num, "prev_char": prev_char, "sec_num": sec_num, "toc_name": matched_toc, "matched_pos": m.start(2), "line_snippet": line[max(0, m.start(2)-20):min(len(line), m.start(2)+40)] }) if file_fixes: print(f"{rel_path}: {len(file_fixes)} confirmed attached TOC section headers") verified_fixes.extend(file_fixes) print(f"\n=== Total Confirmed Attached TOC Section Headers across 45 files: {len(verified_fixes)} ===") with open('scratch/confirmed_attached_headers.json', 'w', encoding='utf-8') as f: json.dump(verified_fixes, f, ensure_ascii=False, indent=2)