import os, sys, re, json sys.stdout.reconfigure(encoding='utf-8') base_dir = "resources/knowledge/original/원가계산/건설공사_표준품셈" 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: if '01_공통부문\\제8장' in os.path.join(root, f) or '01_공통부문/제8장' in os.path.join(root, f): continue all_md_files.append(os.path.join(root, f)) # Also add merged file all_md_files.append(os.path.join(base_dir, "2026년_건설공사_표준품셈.md")) print(f"Auditing {len(all_md_files)} files for 2 flaws...") header_divider_mismatches = [] spec_3row_shift_candidates = [] for fpath in all_md_files: rel_path = os.path.relpath(fpath, base_dir) with open(fpath, 'r', encoding='utf-8') as f: lines = f.readlines() in_table = False header_rows = [] divider_cols = 0 divider_line = 0 for idx, line in enumerate(lines): line_num = idx + 1 line_str = line.strip() if line_str.startswith('|') and line_str.endswith('|'): cells = [c.strip() for c in line_str.split('|')[1:-1]] # Check if this is a divider row if all(re.match(r'^:?-+:?$', c) for c in cells if c): divider_cols = len(cells) divider_line = line_num # Check preceding header row if header_rows: last_hdr = header_rows[-1] if len(last_hdr['cells']) != divider_cols: header_divider_mismatches.append({ "file": rel_path, "line": divider_line, "header_line": last_hdr['line'], "header_cols": len(last_hdr['cells']), "divider_cols": divider_cols, "header_snippet": last_hdr['snippet'] }) in_table = True elif not in_table: header_rows.append({ "line": line_num, "cells": cells, "snippet": line_str[:80] }) else: # Table body row # Check Flaw 1: 3-row spec shifted (e.g. output ㎾ on a row alone or pushed to next line) # Looking for orphaned spec line with ㎾, ton, HP etc. where rest of row is empty or mismatched if len(cells) > 2: c0 = cells[0] c1 = cells[1] if len(cells) > 1 else "" # If first cell is just a unit/spec like "출력 ㎾" or "㎾" and following data columns are misaligned if re.match(r'^(출력|규격|용량)?\s*(\(?㎾\)?|\(?ton\)?|\(?HP\)?|\(?PS\)?)$', c0): spec_3row_shift_candidates.append({ "file": rel_path, "line": line_num, "snippet": line_str[:100] }) else: in_table = False header_rows = [] print(f"\n1. Header vs Divider column mismatches: {len(header_divider_mismatches)}") for m in header_divider_mismatches: print(f" {m['file']} L{m['line']}: header={m['header_cols']} vs divider={m['divider_cols']} ({m['header_snippet']})") print(f"\n2. Spec 3-row shifted candidates: {len(spec_3row_shift_candidates)}") for s in spec_3row_shift_candidates: print(f" {s['file']} L{s['line']}: {s['snippet']}") with open('scratch/laptop_sub_flaws_audit.json', 'w', encoding='utf-8') as f: json.dump({ "header_divider_mismatches": header_divider_mismatches, "spec_3row_shift_candidates": spec_3row_shift_candidates }, f, ensure_ascii=False, indent=2)