""" template — One-Shot YAML Template Generator. Wandelt den inferierten k-ORE/SORE/CHARE regulären Ausdruck zurück in ein menschenlesbares YAML-Skelett für LLM-Prompts. Der Generator erzeugt: - Ein YAML-Grundgerüst mit Platzhaltern - Kommentare mit Kardinalitätshinweisen: * # PFLICHT: Genau 1 mal erforderlich * # PFLICHT: 1 oder mehrmals erforderlich * # OPTIONAL: 0 oder 1 mal (darf weggelassen werden) * # OPTIONAL: 0 oder mehrmals * # WAHLWEISE: alternatives Modul """ def parse_expression(expr): """Zerlegt einen regulären Ausdruck in seine Bestandteile.""" if not expr or expr in ('∅', 'ε', ''): return [('empty', 'ε')] tokens = [] i = 0 while i < len(expr): if expr[i] == '(': depth = 1 j = i + 1 while j < len(expr) and depth > 0: if expr[j] == '(': depth += 1 elif expr[j] == ')': depth -= 1 j += 1 group = expr[i:j] quantifier = '' if j < len(expr) and expr[j] in '*+?': quantifier = expr[j] j += 1 tokens.append(('group', group, quantifier)) i = j elif expr[i] == '|': tokens.append(('pipe', '|')) i += 1 elif expr[i] == '.': if i + 1 < len(expr) and expr[i + 1] == '.': tokens.append(('concat', '..')) i += 2 else: tokens.append(('concat', '.')) i += 1 elif expr[i] in '*+?': if tokens and tokens[-1][0] == 'name': name, val, _ = tokens[-1] tokens[-1] = (name, val, expr[i]) i += 1 elif expr[i].isalnum() or expr[i] in '/_-': j = i while j < len(expr) and (expr[j].isalnum() or expr[j] in '/_-'): j += 1 name = expr[i:j] tokens.append(('name', name, '')) i = j else: i += 1 return tokens def format_prompt_cardinality(quantifier): """Gibt die deutsche Kardinalitätsbeschreibung für einen Quantifier zurück.""" mapping = { '': '# PFLICHT: Genau 1 mal erforderlich', '+': '# PFLICHT: 1 oder mehrmals erforderlich', '*': '# OPTIONAL: 0 oder mehrmals', '?': '# OPTIONAL: 0 oder 1 mal (darf weggelassen werden)', } return mapping.get(quantifier, '') def generate_template(expr, context_key=None, include_header=True): """ Generiert ein YAML-One-Shot-Template aus einem regulären Ausdruck. Args: expr: Der inferierte Ausdruck (String) context_key: Name des YAML-Container-Keys (z.B. 'tasks') include_header: Ob der Header-Teil (name, hosts) eingefügt wird Returns: String: YAML-Skelett mit Platzhaltern und Kardinalitätskommentaren """ if not expr or expr in ('∅', 'ε'): return "# Keine Struktur inferiert (leere Sequenzen oder keine Beispiele)" if include_header: lines = [ "- name: ", " hosts: # PFLICHT: Genau 1 mal erforderlich", ] if context_key: lines.append(f" {context_key}:") else: lines.append(" tasks:") indent = " " else: lines = [] if context_key: lines.append(f" {context_key}: # Container-Kontext: {context_key}") else: lines.append(" tasks:") indent = " " tokens = parse_expression(expr) task_index = 0 skip_until_pipe = False alternatives = [] in_alternatives = False i = 0 while i < len(tokens): token = tokens[i] if token[0] == 'group': group_str = token[1] quantifier = token[2] card = format_prompt_cardinality(quantifier) inner_expr = group_str[1:-1] if '|' in inner_expr: alts = inner_expr.split('|') lines.append(f"{indent}# WAHLWEISE (eines auswählen):") for alt in alts: alt_clean = alt.strip() lines.append(f"{indent}# - {alt_clean}: ") if card: lines[-1] = f"{lines[-1]} {card}" else: lines.append(f"{indent}- {inner_expr}: {card}") task_index += 1 elif token[0] == 'name': name = token[1] quantifier = token[2] card = format_prompt_cardinality(quantifier) lines.append(f"{indent}- {name}: {card}") task_index += 1 elif token[0] == 'pipe': pass i += 1 return '\n'.join(lines) + '\n'