This commit is contained in:
team3
2026-06-27 00:58:46 +02:00
parent 2a2026c9ae
commit f018ca5048
44 changed files with 3070 additions and 379 deletions

View File

@@ -102,16 +102,18 @@ _FRAGMENT_BAUSTEIN_RE = re.compile(r"<!--\s*baustein\s*:\s*(.*?)\s*-->", re.IGNO
# Zwei Lese-Schichten je Section: kompakt (Merksätze) + ausführlich (Erklärung).
_FRAGMENT_KOMPAKT_RE = re.compile(r"<!--\s*kompakt\s*-->", re.IGNORECASE)
_FRAGMENT_AUSF_RE = re.compile(r"<!--\s*ausf(?:ü|ue)hrlich\s*-->", re.IGNORECASE)
_STUFEN = ("einfach", "mittel", "schwer")
# Lernpfad-Stufen + Rand; alte Schwierigkeits-Werte abwärtskompatibel akzeptiert.
_STUFEN = ("anfaenger", "fortgeschritten", "experte", "rand", "einfach", "mittel", "schwer")
def _parse_fragment(text: str) -> list[dict]:
"""Parst eine Writer-Datei → [{"kapitel", "titel", "md", "kompakt", "subs"}] in Reihenfolge.
"""Parst eine Writer-Datei → [{kapitel, titel, md, kompakt, anker, anker_kompakt, subs}].
Zwei optionale Lese-Schichten je Section über `<!-- kompakt -->` / `<!-- ausführlich -->`:
Zeilen nach `kompakt` landen in `sec["kompakt"]`, sonst in `sec["md"]` (= ausführlich,
auch der Default ohne Marker → rückwärtskompatibel). Optionale `<!-- sub: -->`-Marker
sammeln sich weiter in `sec["subs"]`.
Zwei Lese-Schichten je Section über `<!-- kompakt -->` / `<!-- ausführlich -->`. Innerhalb
beider markieren `<!-- sub: stufe | titel -->`-Marker je Subbaustein einen Block; gleicher
Sub-Titel in beiden Schichten wird gemergt → `sec["subs"] = [{stufe, titel, md, kompakt}]`.
Text VOR dem ersten Sub-Marker ist der Anker (Einordnung) → `anker`/`anker_kompakt`.
`md`/`kompakt` bleiben die VOLLE Fassung (Anker + alle Subs) — rückwärtskompatibel.
"""
sections: list[dict] = []
kapitel = None
@@ -128,7 +130,8 @@ def _parse_fragment(text: str) -> list[dict]:
continue
m = _FRAGMENT_SECTION_RE.match(s)
if m:
current = {"kapitel": kapitel, "titel": m.group(1), "md": [], "kompakt": [], "subs": []}
current = {"kapitel": kapitel, "titel": m.group(1), "md": [], "kompakt": [],
"anker_md": [], "anker_kompakt": [], "_submap": {}, "_suborder": []}
cur_sub = None
cur_layer = "md"
sections.append(current)
@@ -145,24 +148,40 @@ def _parse_fragment(text: str) -> list[dict]:
if m and current is not None:
teil = m.group(1).split("|", 1)
stufe = teil[0].strip().casefold()
cur_sub = {
"stufe": stufe if stufe in _STUFEN else "einfach",
"titel": teil[1].strip() if len(teil) == 2 else "",
"md": [],
}
current["subs"].append(cur_sub)
titel = teil[1].strip() if len(teil) == 2 else ""
key = titel.casefold() or f"_pos{len(current['_suborder'])}"
cur_sub = current["_submap"].get(key)
if cur_sub is None:
cur_sub = {"stufe": stufe if stufe in _STUFEN else "anfaenger", "titel": titel, "md": [], "kompakt": []}
current["_submap"][key] = cur_sub
current["_suborder"].append(key)
elif stufe in _STUFEN:
cur_sub["stufe"] = stufe
continue
if current is not None:
current[cur_layer].append(line)
if cur_sub is not None and cur_layer == "md":
cur_sub["md"].append(line)
if cur_sub is not None:
cur_sub[cur_layer].append(line)
else:
current["anker_" + cur_layer].append(line)
out: list[dict] = []
for sec in sections:
sec["md"] = "\n".join(sec["md"]).strip()
sec["kompakt"] = "\n".join(sec["kompakt"]).strip()
for sub in sec["subs"]:
subs = []
for key in sec["_suborder"]:
sub = sec["_submap"][key]
sub["md"] = "\n".join(sub["md"]).strip()
sec["subs"] = [sub for sub in sec["subs"] if sub["md"]]
return sections
sub["kompakt"] = "\n".join(sub["kompakt"]).strip()
if sub["md"] or sub["kompakt"]:
subs.append(sub)
out.append({
"kapitel": sec["kapitel"], "titel": sec["titel"],
"md": "\n".join(sec["md"]).strip(),
"kompakt": "\n".join(sec["kompakt"]).strip(),
"anker": "\n".join(sec["anker_md"]).strip(),
"anker_kompakt": "\n".join(sec["anker_kompakt"]).strip(),
"subs": subs,
})
return out
def _parse_subbausteine(text: str) -> dict[str, list[str]]: