Files
buchwerk/backend/gliederung.py
2026-09-27 21:36:33 +02:00

53 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Parser für buch/GLIEDERUNG.md (Format siehe prompts/gliederung.md)."""
import re
KAPITEL_RE = re.compile(r"^\*\*Kapitel (\d+) – (.+?)\*\* \(`([0-9]{2}-[a-z0-9-]+\.md)`\)\s*$")
TEIL_RE = re.compile(r"^## (Teil .+?)\s*$")
TITEL_RE = re.compile(r"^# Gliederung – (.+?)(?:\. (.+))?$")
def parsen(text: str) -> dict:
"""→ {"titel", "untertitel", "kapitel": [{"n","titel","datei","teil","abschnitte":[{"nr","titel"}]}], "fehler": [...]}"""
aus = {"titel": "", "untertitel": "", "kapitel": [], "fehler": []}
teil = ""
zeilen = text.splitlines()
i = 0
while i < len(zeilen):
z = zeilen[i].rstrip()
m = TITEL_RE.match(z)
if m and not aus["titel"]:
aus["titel"], aus["untertitel"] = m.group(1).strip(), (m.group(2) or "").strip()
elif TEIL_RE.match(z):
teil = TEIL_RE.match(z).group(1)
elif KAPITEL_RE.match(z):
m = KAPITEL_RE.match(z)
n = int(m.group(1))
k = {"n": n, "titel": m.group(2).strip(), "datei": m.group(3), "teil": teil, "abschnitte": []}
# nächste nicht-leere Zeile: Abschnitte
j = i + 1
while j < len(zeilen) and not zeilen[j].strip():
j += 1
if j < len(zeilen):
for teilstueck in re.split(r"\s+·\s+", zeilen[j].strip()):
am = re.match(r"^(\d+)\.(\d+)\s+(.+)$", teilstueck.strip())
if am and int(am.group(1)) == n:
k["abschnitte"].append({"nr": f"{am.group(1)}.{am.group(2)}", "titel": am.group(3).strip()})
else:
aus["fehler"].append(f"Kapitel {n}: Abschnittszeile unlesbar: „{teilstueck.strip()[:60]}“")
i = j
if not k["datei"].startswith(f"{n:02d}-"):
aus["fehler"].append(f"Kapitel {n}: Dateiname muss mit {n:02d}- beginnen ({k['datei']})")
aus["kapitel"].append(k)
elif z.startswith("**Kapitel"):
aus["fehler"].append(f"Kapitelzeile nicht im Format: „{z[:80]}“")
i += 1
for k in aus["kapitel"]:
if not 3 <= len(k["abschnitte"]) <= 6:
aus["fehler"].append(f"Kapitel {k['n']} hat {len(k['abschnitte'])} Abschnitte (3–6 verlangt)")
nummern = [k["n"] for k in aus["kapitel"]]
if nummern != list(range(1, len(nummern) + 1)):
aus["fehler"].append(f"Kapitelnummern nicht fortlaufend: {nummern}")
if not aus["kapitel"]:
aus["fehler"].append("Keine Kapitelzeile gefunden")
return aus