"""DXF 파일명에서 구조물 종류를 자동 추정. 토목 설계 도면 파일명에는 보통 구조물 종류가 포함됨: "여수로 수문 설치도.dxf" → spillway_gate "좌안옹벽 일반도.dxf" → retaining_wall "신설 취수탑 설비 설치도.dxf" → building "OO 교량 상세도.dxf" → bridge "터널 갱구 설치도.dxf" → tunnel_portal 사용법: from filename_classifier import classify_by_filename tid = classify_by_filename("좌안옹벽 일반도.dxf") # → "retaining_wall" """ from __future__ import annotations import re from pathlib import Path from typing import Optional # --------------------------------------------------------------------------- # 구조물 유형별 키워드 패턴 # --------------------------------------------------------------------------- # 우선순위가 높은 것을 먼저 (더 구체적인 패턴 → 일반적인 패턴) FILENAME_PATTERNS = { "spillway_gate": [ # 여수로 수문 관련 r"여수로.*수문", r"수문.*여수로", r"여수로.*게이트", r"래디얼.*게이트", r"테인터.*게이트", r"tainter.*gate", r"radial.*gate", r"spillway.*gate", r"spillway", # 수문 단독 r"(? Optional[str]: """파일명에서 구조물 유형을 추정. Args: filename: 파일 경로 또는 파일명 Returns: template_id 문자열 ("spillway_gate", "building" 등) 또는 확실한 매칭이 없으면 None """ # 파일명만 추출 (경로/확장자 제거) name = Path(filename).stem.lower() # 구두점/숫자 코드 노이즈 제거 (예: "12995740-M40-001") # 한글/영문 단어만 남김 cleaned = re.sub(r"[\d\-_/\\]+", " ", name) cleaned = re.sub(r"\s+", " ", cleaned).strip() # 주 키워드 우선 매칭 for template_id, patterns in FILENAME_PATTERNS.items(): for pat in patterns: if re.search(pat, cleaned, re.IGNORECASE): return template_id # 보조 키워드로 재시도 best_id = None best_count = 0 for template_id, keywords in SECONDARY_KEYWORDS.items(): count = sum(1 for kw in keywords if kw.lower() in cleaned) if count > best_count: best_count = count best_id = template_id if best_count >= 1: return best_id return None def classify_by_filenames(filenames: list[str]) -> Optional[str]: """여러 파일의 이름을 종합해서 가장 가능성 높은 유형 추정.""" votes = {} for f in filenames: tid = classify_by_filename(f) if tid: votes[tid] = votes.get(tid, 0) + 1 if not votes: return None # 최다 득표 return max(votes.items(), key=lambda x: x[1])[0] def suggest_with_confidence(filename: str) -> tuple[Optional[str], float]: """추정 결과 + 신뢰도 반환. Returns: (template_id, confidence): confidence ∈ [0.0, 1.0] """ name = Path(filename).stem.lower() cleaned = re.sub(r"[\d\-_/\\]+", " ", name) cleaned = re.sub(r"\s+", " ", cleaned).strip() # 주 키워드 매칭 개수 및 매칭된 패턴 확인 for template_id, patterns in FILENAME_PATTERNS.items(): matched_patterns = [] for pat in patterns: if re.search(pat, cleaned, re.IGNORECASE): matched_patterns.append(pat) if matched_patterns: # 매칭 개수에 따라 신뢰도 계산 # 1개 매칭 → 0.75, 2개 → 0.85, 3개+ → 0.95 conf = min(0.95, 0.65 + 0.1 * len(matched_patterns)) return template_id, conf # 보조 키워드 시도 for template_id, keywords in SECONDARY_KEYWORDS.items(): matched = [kw for kw in keywords if kw.lower() in cleaned] if matched: conf = min(0.6, 0.3 + 0.1 * len(matched)) return template_id, conf return None, 0.0 # --------------------------------------------------------------------------- # 테스트 # --------------------------------------------------------------------------- if __name__ == "__main__": test_cases = [ "12995740-M40-001 여수로 수문 설치도(1/2).dxf", "12995740-M40-002 여수로 수문 설치도(2/2).dxf", "12996710-M40-001 신설 취수탑 설비 설치도(1/2).dxf", "12996710-M40-002 신설 취수탑 설비 설치도(2/2).dxf", "12996710-M43-002 신설 제수변실 설비 배치도.dxf", "1. 좌안옹벽 일반도 작성(2026.0109).dxf", "사연댐 전체계획 평면도.dxf", "A-Line 교량 상세도.dxf", "B-Road 터널 갱구 일반도.dxf", "관리사무소 평면도.dxf", "P-Station 펌프장 설치도.dxf", "random_file.dxf", ] print("파일명 기반 구조물 유형 추정:") print("=" * 70) for f in test_cases: tid, conf = suggest_with_confidence(f) if tid: print(f" [{tid:16}] ({conf:.0%}) {f}") else: print(f" [{'─' * 16}] (미매칭) {f}")