import sys, os, re, json sys.stdout.reconfigure(encoding='utf-8') md_files = [ ("공통_제1장", "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제1장_적용기준.md"), ("공통_제3장", "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제3장_토공사.md"), ("공통_제4장", "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제4장_조경공사.md"), ("공통_제6장", "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제6장_철근콘크리트공사.md"), ("토목_제1장", "resources/knowledge/original/원가계산/건설공사_표준품셈/02_토목부문/제1장_도로포장공사.md"), ("토목_제6장", "resources/knowledge/original/원가계산/건설공사_표준품셈/02_토목부문/제6장_관부설및접합공사.md"), ("건축_제9장", "resources/knowledge/original/원가계산/건설공사_표준품셈/03_건축부문/제9장_미장공사.md"), ("유지관리_제1장", "resources/knowledge/original/원가계산/건설공사_표준품셈/05_유지관리부문/제1장_공통.md"), ("유지관리_제3장", "resources/knowledge/original/원가계산/건설공사_표준품셈/05_유지관리부문/제3장_건축.md"), ] report = {} for label, path in md_files: if not os.path.exists(path): continue with open(path, 'r', encoding='utf-8') as f: lines = f.readlines() print(f"\n=======================================================") print(f"Scanning {label} ({os.path.basename(path)}) - {len(lines)} lines") file_issues = { "attached_section_headers": [], "collapsed_table_rows": [], "attached_notes_tail": [], "page_transition_artifacts": [] } for idx, line in enumerate(lines): line_num = idx + 1 line_clean = line.strip() # 1. Attached section headers: e.g. text ending immediately with 1-2-2 or 3-4-1 without newline m_sec = re.findall(r'([^\s#\-\*\>\|])(\d+-\d+(?:-\d+)?)', line) for prev_char, sec_num in m_sec: # check if it looks like a real section header if prev_char not in ['제', '표', '·', '(', '/', '-', ',', ':']: file_issues["attached_section_headers"].append({ "line": line_num, "prev_char": prev_char, "sec_num": sec_num, "snippet": line_clean[:120] }) # 2. Collapsed table rows: table row with extreme length or multiple repeated patterns in single cell if line_clean.startswith('|') and line_clean.endswith('|'): cells = [c.strip() for c in line_clean.split('|')[1:-1]] for c in cells: # if cell has multiple words separated by space that look like collapsed table rows (e.g. 5 or more items) tokens = c.split() if len(tokens) >= 15: file_issues["collapsed_table_rows"].append({ "line": line_num, "token_count": len(tokens), "snippet": c[:100] + "..." }) break # 3. Page transition artifacts: e.g. "→4공통부문" or "3제1장 적용기준" m_page = re.findall(r'(?:→\d+|\d+제\d+장|\d+공통부문|\d+토목부문|\d+건축부문|\d+유지관리부문)', line) if m_page: file_issues["page_transition_artifacts"].append({ "line": line_num, "artifacts": m_page, "snippet": line_clean[:100] }) # 4. Attached notes tail: [주] ending with next section immediately if '[주]' in line or '주]' in line: m_tail = re.findall(r'(\[주\].*?)(\d+-\d+)', line) if m_tail: file_issues["attached_notes_tail"].append({ "line": line_num, "snippet": line_clean[:100] }) print(f" - Attached section headers: {len(file_issues['attached_section_headers'])}") print(f" - Collapsed table rows: {len(file_issues['collapsed_table_rows'])}") print(f" - Attached notes tails: {len(file_issues['attached_notes_tail'])}") print(f" - Page transition artifacts: {len(file_issues['page_transition_artifacts'])}") report[label] = file_issues with open('scratch/const_md_flaws_scan.json', 'w', encoding='utf-8') as f: json.dump(report, f, ensure_ascii=False, indent=2)