fixed complex strings

This commit is contained in:
2026-09-02 14:18:40 +03:00
parent b014033fbb
commit 3d0bd8e0c9
3 changed files with 69 additions and 37 deletions
+4 -10
View File
@@ -446,17 +446,11 @@ class AltiumParser:
def make_complex_string(text: str, props: list[ComponentProperty]) -> str: def make_complex_string(text: str, props: list[ComponentProperty]) -> str:
text = sanitize_text(text) from app.services.designators import resolve_expression
if not text.startswith("="):
return text
expr = text[1:]
mapping = {p.name: p.text for p in props} mapping = {p.name: p.text for p in props}
designator = mapping.get("Designator", "")
def repl(m: re.Match) -> str: return sanitize_text(resolve_expression(text, mapping, designator))
key = m.group(1)
return mapping.get(key, "")
return sanitize_text(re.sub(r"['\"]([^'\"]+)['\"]", repl, expr))
def find_prjpcb(extract_dir: Path) -> Optional[Path]: def find_prjpcb(extract_dir: Path) -> Optional[Path]:
+60 -26
View File
@@ -146,33 +146,67 @@ def split_long_text(text: str, max_length: int) -> list[str]:
return parts or [""] return parts or [""]
def resolve_expression(value: str, props: dict[str, str]) -> str: def _split_expression_parts(expr: str) -> list[str]:
"""Split Altium expression by + outside quotes."""
parts: list[str] = []
current: list[str] = []
in_double = False
in_single = False
for ch in expr:
if ch == '"' and not in_single:
in_double = not in_double
current.append(ch)
elif ch == "'" and not in_double:
in_single = not in_single
current.append(ch)
elif ch == "+" and not in_double and not in_single:
if current:
parts.append("".join(current).strip())
current = []
else:
current.append(ch)
if current:
parts.append("".join(current).strip())
return parts
def _resolve_property(name: str, props: dict[str, str], designator: str = "") -> str:
if name == "Designator":
raw = designator or props.get("Designator", "")
else:
raw = props.get(name, "")
if not raw:
return ""
if raw.startswith("=") or (raw.startswith('"') and raw.endswith('"') and len(raw) > 1):
return resolve_expression(raw, props, designator)
return raw
def resolve_expression(value: str, props: dict[str, str], designator: str = "") -> str:
"""
Altium complex string: ='literal'+"Property"+Name
- single quotes = literal text
- double quotes = component property reference
- bare identifiers = property reference
"""
if not value:
return ""
value = value.strip()
if value.startswith('"') and value.endswith('"') and not value.startswith('="'):
return _resolve_property(value[1:-1], props, designator)
if not value.startswith("="): if not value.startswith("="):
return value return value
expr = value[1:]
result = [] result: list[str] = []
i = 0 for part in _split_expression_parts(value[1:]):
while i < len(expr): if not part:
ch = expr[i] continue
if ch in "'\"": if part.startswith("'") and part.endswith("'") and len(part) >= 2:
quote = ch result.append(part[1:-1])
i += 1 elif part.startswith('"') and part.endswith('"') and len(part) >= 2:
start = i result.append(_resolve_property(part[1:-1], props, designator))
while i < len(expr) and expr[i] != quote: elif part == "Designator":
i += 1 result.append(designator or props.get("Designator", ""))
result.append(expr[start:i])
i += 1
elif ch == "+":
i += 1
elif ch.isspace():
i += 1
else: else:
start = i result.append(_resolve_property(part, props, designator))
while i < len(expr) and expr[i] not in "+'\"":
i += 1
key = expr[start:i].strip()
val = props.get(key, "")
if val.startswith("="):
val = resolve_expression(val, props)
result.append(val)
return "".join(result) return "".join(result)
+5 -1
View File
@@ -24,8 +24,12 @@ class ComponentView:
is_fitted: bool = True is_fitted: bool = True
def get(self, key: str, default: str = "") -> str: def get(self, key: str, default: str = "") -> str:
if key == "Designator":
return self.designator or self.properties.get("Designator", default)
raw = self.properties.get(key, default) raw = self.properties.get(key, default)
return resolve_expression(raw, self.properties) if raw else default if not raw:
return default
return resolve_expression(raw, self.properties, self.designator)
@dataclass @dataclass