20251117_104033 기준 데이터
This commit is contained in:
160
데이터수집/수집스크립트/custom_property_parser.py
Normal file
160
데이터수집/수집스크립트/custom_property_parser.py
Normal file
@ -0,0 +1,160 @@
|
||||
# -*- 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
|
||||
Reference in New Issue
Block a user