Files
DS-Combat_analy/데이터수집/수집스크립트/custom_property_parser.py

161 lines
3.9 KiB
Python
Raw Normal View History

2025-11-17 16:56:36 +09:00
# -*- coding: utf-8 -*-
"""
CustomProperties 문자열 파싱 유틸리티
AnimMontage의 AnimNotifies에 있는 CustomProperties는 모두 문자열로 저장되어 있어서
타입 변환 파싱이 필요합니다.
"""
import re
from typing import Any, Optional
def parse_float(value: str) -> Optional[float]:
"""문자열을 float로 변환 (실패 시 None)"""
try:
return float(value.strip())
except (ValueError, AttributeError):
return None
def parse_tag_name(value: str) -> Optional[str]:
"""
(TagName="Event.Attack.Normal") 형태에서 태그 이름 추출
Example:
'(TagName="Event.Attack.Normal")' -> 'Event.Attack.Normal'
"""
if not value:
return None
match = re.search(r'TagName="([^"]+)"', value)
if match:
return match.group(1)
return None
def parse_vector(value: str) -> Optional[dict]:
"""
(X=0.0,Y=1.0,Z=0.0) 형태를 dict로 변환
Example:
'(X=0.0,Y=1.0,Z=0.0)' -> {'X': 0.0, 'Y': 1.0, 'Z': 0.0}
"""
if not value:
return None
try:
x_match = re.search(r'X=([-\d.]+)', value)
y_match = re.search(r'Y=([-\d.]+)', value)
z_match = re.search(r'Z=([-\d.]+)', value)
if x_match and y_match and z_match:
return {
'X': float(x_match.group(1)),
'Y': float(y_match.group(1)),
'Z': float(z_match.group(1))
}
except (ValueError, AttributeError):
pass
return None
def parse_array(value: str) -> Optional[list]:
"""
(0.1,0.2,0.3) 형태를 리스트로 변환
Example:
'(0.1,0.2,0.3)' -> [0.1, 0.2, 0.3]
"""
if not value:
return None
try:
# 괄호 제거
cleaned = value.strip().strip('()')
if not cleaned:
return []
# 쉼표로 분리
parts = cleaned.split(',')
return [float(p.strip()) for p in parts if p.strip()]
except (ValueError, AttributeError):
return None
def parse_custom_property(value: str, field_name: str) -> Any:
"""
CustomProperties 필드의 값을 적절한 타입으로 변환
Args:
value: 원본 문자열
field_name: 필드 이름 (타입 추론에 사용)
Returns:
파싱된 (float, str, dict, list )
"""
if not isinstance(value, str):
return value
value = value.strip()
# 빈 문자열
if not value or value == '':
return None
# TagName 파싱
if 'TagName=' in value:
tag = parse_tag_name(value)
if tag and tag != 'None':
return tag
return None
# Vector 파싱
if value.startswith('(') and ('X=' in value or 'Y=' in value or 'Z=' in value):
vec = parse_vector(value)
if vec:
return vec
# Array 파싱 (TimeArray, LocationArray 등)
if 'Array' in field_name and value.startswith('('):
arr = parse_array(value)
if arr is not None:
return arr
# Boolean 파싱
if value.lower() in ['true', 'false']:
return value.lower() == 'true'
# Float 파싱 시도
float_val = parse_float(value)
if float_val is not None:
return float_val
# 기본: 문자열 그대로 반환
return value
def extract_notify_properties(notify: dict, target_fields: list) -> dict:
"""
AnimNotify에서 CustomProperties의 특정 필드만 추출
Args:
notify: AnimNotify 딕셔너리
target_fields: 추출할 필드 이름 리스트
Returns:
추출된 프로퍼티 딕셔너리
"""
custom_props = notify.get('CustomProperties', {})
result = {}
for field in target_fields:
if field in custom_props:
value = custom_props[field]
parsed = parse_custom_property(value, field)
if parsed is not None:
result[field] = parsed
return result