from __future__ import annotations from dataclasses import dataclass from pathlib import Path TYPE_MAP = { "aFLOAT": "R", "aBYTE": "B", "aSTRING": "S", "aCMPLX": "C", "aLIST": "L", "aWORD10": "W", "aLONG": "G", "aNotUsed": "?", } @dataclass(frozen=True) class ObjectDef: name: str object_id: int geometry_code: str display_code: str | None description: str | None raw_line: str @dataclass(frozen=True) class AttributeDef: name: str attribute_id: int source_type_name: str decoder_type: str min_value: float | None max_value: float | None raw_line: str def _read_lines(path: Path): for enc in ("utf-8-sig", "cp1252", "latin1"): try: return path.read_text(encoding=enc).splitlines() except UnicodeDecodeError: pass raise UnicodeDecodeError("unknown", b"", 0, 1, f"无法读取 {path}") def load_object_dictionary(path: Path) -> list[ObjectDef]: out = [] for line in _read_lines(path): if not line.strip(): continue parts = line.rstrip("\r\n").split("|") if len(parts) < 3: continue try: object_id = int(parts[1].strip()) except ValueError: continue out.append(ObjectDef( name=parts[0].strip(), object_id=object_id, geometry_code=parts[2].strip(), display_code=parts[3].strip() if len(parts) > 3 else None, description=parts[4].strip() if len(parts) > 4 else None, raw_line=line, )) return out def load_attribute_dictionary(path: Path) -> list[AttributeDef]: out = [] for line in _read_lines(path): if not line.strip(): continue parts = [p.strip() for p in line.rstrip("\r\n").split("|")] if len(parts) < 3: continue try: attribute_id = int(parts[1]) except ValueError: continue source_type = parts[2] def f(i): if len(parts) <= i or parts[i] == "": return None try: return float(parts[i]) except ValueError: return None out.append(AttributeDef( name=parts[0], attribute_id=attribute_id, source_type_name=source_type, decoder_type=TYPE_MAP.get(source_type, "?"), min_value=f(3), max_value=f(4), raw_line=line, )) return out