import os, sys, re, json sys.stdout.reconfigure(encoding='utf-8') base_dir = "resources/knowledge/original/원가계산/건설공사_표준품셈" # Target files for Antigravity: # 1. 02_토목부문/* # 2. 05_유지관리부문/* # 3. 04_기계설비부문/제13장_플랜트설비공사.md target_files = [] for root, dirs, files in os.walk(base_dir): for f in files: if not f.endswith('.md') or f.startswith('_') or '개정사항' in f: continue rel = os.path.relpath(os.path.join(root, f), base_dir) if rel.startswith("02_토목부문") or rel.startswith("05_유지관리부문") or rel == os.path.join("04_기계설비부문", "제13장_플랜트설비공사.md"): target_files.append(os.path.join(root, f)) print(f"Target files in scope: {len(target_files)}") # Criteria for "값이 한 칸에 여럿 든 것": # In a markdown table row: # - A cell contains multiple tokens separated by space, where tokens look like: # a) Multiple numeric values (e.g. "12 10", "70 90 110", "0.05 0.03") # b) Multiple job titles (e.g. "착암공 보통인부", "철골공 용접공 보통인부") # c) Multiple units (e.g. "인 인", "인 인 대") # d) Multiple specs (e.g. "5m이하 6~8m 9~11m") # Note: Exclude header rows (|---|---|) and rows that are descriptions or notes results = [] job_titles = ["인부", "공", "사", "부", "조"] # common job title endings unit_tokens = ["인", "대", "hr", "시간", "m", "㎡", "㎥", "ton", "㎏", "본", "조", "개소", "회", "매", "식", "km", "ℓ", "L"] for fpath in sorted(target_files): rel = os.path.relpath(fpath, base_dir) with open(fpath, 'r', encoding='utf-8') as f: lines = f.readlines() in_table = False for idx, line in enumerate(lines): line_num = idx + 1 line_str = line.strip() if not (line_str.startswith('|') and line_str.endswith('|')): in_table = False continue cells = [c.strip() for c in line_str.split('|')[1:-1]] # Check divider if all(re.match(r'^:?-+:?$', c) for c in cells if c): in_table = True continue if not in_table: # Could be header rows before divider continue # Check if row is a note/비고 row (e.g. first cell is "비고", "주", "[주]") if cells and cells[0] in ["비고", "비 고", "주", "[주]", "참고"]: continue # Inspect cells for multiple values has_multi_val = False reasons = [] for c_idx, c in enumerate(cells): tokens = c.split() if len(tokens) <= 1: continue # Case 1: Multiple units (e.g. "인 인", "인 대") if len(tokens) >= 2 and all(tok in unit_tokens for tok in tokens): has_multi_val = True reasons.append(f"col{c_idx}: multi-units ({c})") # Case 2: Multiple job titles (e.g. "철골공 용접공 보통인부", "착암공 보통인부") elif len(tokens) >= 2 and all(any(tok.endswith(j) for j in job_titles) for tok in tokens): has_multi_val = True reasons.append(f"col{c_idx}: multi-jobs ({c})") # Case 3: Multiple numbers (e.g. "1 2 1", "70 90 110", "12 10") elif len(tokens) >= 2 and sum(1 for tok in tokens if re.match(r'^-?\d+(?:\.\d+)?(?:∼\d+(?:\.\d+)?)?%?$', tok)) >= 2: # But check if it's a range like "10 ~ 20" which split might produce if space if len(tokens) == 3 and tokens[1] in ['~', '∼', '-', '―', 'to']: pass # it's a range else: # check if at least 2 tokens are standalone numbers num_toks = [t for t in tokens if re.match(r'^-?\d+(?:\.\d+)?$', t)] if len(num_toks) >= 2: has_multi_val = True reasons.append(f"col{c_idx}: multi-numbers ({c[:40]})") # Case 4: Multiple specs (e.g. "5m이하 6~8m 9~11m") elif len(tokens) >= 2 and all(any(char.isdigit() for char in tok) and any(unit in tok for unit in ['m', '㎜', 'ton', '㎥', '㎡', '이하', '초과', '미만']) for tok in tokens): has_multi_val = True reasons.append(f"col{c_idx}: multi-specs ({c[:40]})") if has_multi_val: results.append({ "file": rel, "line": line_num, "reasons": reasons, "cells": cells, "raw_line": line_str[:120] }) print(f"\nTotal multi-value rows found in Antigravity scope: {len(results)}") by_file = {} for r in results: f = r['file'] by_file[f] = by_file.get(f, 0) + 1 for f, cnt in sorted(by_file.items(), key=lambda x: x[1], reverse=True): print(f" {cnt:3d} rows: {f}") with open('scratch/wide_criteria_my_scope.json', 'w', encoding='utf-8') as f: json.dump(results, f, ensure_ascii=False, indent=2)