124 lines
5.1 KiB
Python
124 lines
5.1 KiB
Python
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)
|