import os, sys, re, json, glob sys.stdout.reconfigure(encoding='utf-8') base_dir = 'resources/knowledge/original/원가계산/건설공사_표준품셈' divisions = ['02_토목부문', '03_건축부문', '04_기계설비부문', '05_유지관리부문'] risk_tables = [] for div in divisions: div_path = os.path.join(base_dir, div) if not os.path.exists(div_path): continue md_files = sorted(glob.glob(os.path.join(div_path, '*.md'))) for fpath in md_files: fname = os.path.basename(fpath) if fname.startswith('_') or '개정사항' in fname: continue with open(fpath, 'r', encoding='utf-8') as f: lines = f.readlines() current_sec = 'UNKNOWN' in_table = False headers = [] table_rows = [] start_line = 0 for idx, line in enumerate(lines): line_s = line.strip() sec_m = re.search(r'(\d+-\d+(?:-\d+)?(?:\s+[^\n(]+)?)', line_s) if sec_m and not line_s.startswith('|'): current_sec = sec_m.group(1).strip() if line_s.startswith('|') and not line_s.startswith('|---'): cols = [c.strip() for c in line_s.split('|')[1:-1]] if not in_table: # check if table starts headers = cols in_table = True start_line = idx + 1 table_rows = [] continue if in_table: table_rows.append((idx + 1, cols)) else: if in_table and (line_s == '' or not line_s.startswith('|')): # Evaluate table for risk criteria # 1. Condition or remarks across multiple rows # 2. No classification code, split only by condition # 3. Efficiency, coefficient, factor tables header_text = " ".join(headers) table_all_text = header_text + " " + " ".join([" ".join(r[1]) for r in table_rows]) is_risk = False risk_reasons = [] # Rule 1: Efficiency / coefficient / factor table if any(k in header_text for k in ['효율', '작업효율', '계수', '할증', '보정', '손실률', '환산', '증감']): is_risk = True risk_reasons.append('효율/계수/할증 표') elif any(k in current_sec for k in ['효율', '계수', '할증']): is_risk = True risk_reasons.append('효율/계수 섹션') # Rule 2: Remarks column present with multiple rows if any('비고' in h or '비 고' in h for h in headers) and len(table_rows) >= 2: rem_idx = [i for i, h in enumerate(headers) if '비고' in h or '비 고' in h][0] non_empty_rem = [r[1][rem_idx] for r in table_rows if rem_idx < len(r[1]) and r[1][rem_idx]] if len(non_empty_rem) >= 1: is_risk = True risk_reasons.append('비고 열 보유 다중행') # Rule 3: Conditions branching (no job category/worker in headers, just conditions) condition_kws = ['조건', '지형', '토질', '수심', '암질', '두께', '경사', '규격', '차단', '구분'] if any(k in header_text for k in condition_kws) and not any(k in header_text for k in ['직종', '인부', '기술자', '기능사']): # Table has conditions, possibly matrix/coefficient if len(table_rows) >= 2: is_risk = True risk_reasons.append('조건 분기 표 (직종 없음)') # Rule 4: Col 0 has merged or multi-level values col0_vals = [r[1][0] for r in table_rows if len(r[1]) > 0] if any(v == '' for v in col0_vals) or any('→' in v for v in col0_vals): is_risk = True risk_reasons.append('Col 0 빈칸/연결(병합/다단)') if is_risk: risk_tables.append({ 'division': div, 'file': fname, 'sec': current_sec, 'start_line': start_line, 'rows': len(table_rows), 'headers': headers, 'reasons': risk_reasons, 'col0_sample': col0_vals[:4] }) in_table = False headers = [] table_rows = [] print(f"Total Risk Tables found: {len(risk_tables)}") by_file = {} for rt in risk_tables: k = f"{rt['division']}/{rt['file']}" by_file.setdefault(k, []).append(rt) for k, v in by_file.items(): print(f"\n[{k}] : {len(v)} risk tables") for item in v[:5]: print(f" - L{item['start_line']} {item['sec']} ({', '.join(item['reasons'])}) : {item['headers']}") if len(v) > 5: print(f" ... and {len(v)-5} more") with open('scratch/risk_tables_list.json', 'w', encoding='utf-8') as f: json.dump(risk_tables, f, ensure_ascii=False, indent=2)