This commit is contained in:
team3
2026-07-24 11:23:18 +02:00
parent cb68cd671b
commit 1b054497ed
49 changed files with 935 additions and 408 deletions

View File

@@ -6,14 +6,17 @@ import unicodedata
from . import config
# Sprache kommt aus config.SPRACHE (Lektion 106) — kein hartkodiertes Deutsch
try:
import Stemmer
_stemmer = Stemmer.Stemmer("german")
_name = config.STEMMER_NAME.get(config.SPRACHE)
_stemmer = Stemmer.Stemmer(_name) if _name else None
except ImportError: # Fallback ohne C-Extension: ungestemmt
_stemmer = None
_WORT_RE = re.compile(r"[a-zäöüß0-9]+")
_NEGATION = {"nicht", "kein", "keine", "keinen", "keiner", "nie", "niemals", "ohne"}
_WORT_RE = re.compile(r"\w+", re.UNICODE) # alle Schriften, nicht nur Latein
_NEGATION = config.NEGATIONEN.get(config.SPRACHE, set())
_NEG_PRAEFIX = config.NEGATIONS_PRAEFIX.get(config.SPRACHE, "\0")
def norm(text: str) -> str:
@@ -37,9 +40,10 @@ def jaccard(a: str, b: str, gestemmt: bool = True) -> float:
def negations_menge(text: str) -> frozenset:
"""Antonyme messen 0.91-0.95 Cosinus (Lektion 31) — harte Merge-Vorbedingung."""
"""Antonyme messen 0.91-0.95 Cosinus (Lektion 31) — harte Merge-Vorbedingung.
Lexikon je Sprache; ohne Eintrag ist der Guard bewusst aus (dokumentiert)."""
t = tokens(text)
return frozenset(w for w in t if w in _NEGATION or w.startswith("nicht"))
return frozenset(w for w in t if w in _NEGATION or w.startswith(_NEG_PRAEFIX))
def titel_kern(titel: str) -> str:
@@ -81,19 +85,34 @@ def ueberlappung(a: tuple[int, int], b: tuple[int, int]) -> float:
return schnitt / kuerzer if kuerzer > 0 else 0.0
_SATZ_RE = re.compile(r"(?<=[.!?])\s+(?=[A-ZÄÖÜ])")
_SATZ_RE = re.compile(r"(?<=[.!?])\s+")
def satz_split(text: str) -> list[str]:
"""Terminator + Whitespace; Teile, die klein weitergehen (Abkürzungen,
„z. B."), werden wieder angefügt — Unicode-Groß statt [A-ZÄÖÜ]-Klasse."""
saetze = []
for absatz in text.split("\n"):
absatz = absatz.strip()
if not absatz or absatz.startswith(("#", "```", "|", "<!--")):
continue
saetze += [s.strip() for s in _SATZ_RE.split(absatz) if s.strip()]
for teil in _SATZ_RE.split(absatz):
teil = teil.strip()
if not teil:
continue
if saetze and teil[0].islower():
saetze[-1] += " " + teil
else:
saetze.append(teil)
return saetze
def paar_liste(paare: list[tuple[str, str]]) -> str:
"""EIN Paar-Rendering für alle Paar-Urteils-Aufgaben (dedup, redundanz)."""
return "\n\n".join(f"PAAR {i + 1}:\nA: {a}\nB: {b}"
for i, (a, b) in enumerate(paare))
# ── Positions-Maps für Anker-Suche ──
def _map_bauen(text: str, wandler) -> tuple[str, list[int]]: