From 3a8cab87c231cc0fb76b78a276075d705b714c02 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Thu, 10 Sep 2026 01:30:44 +0200 Subject: [PATCH] spaCy-Kandidaten-Skript verworfen, Dateien entfernt --- .../erzeuge_stichwortkandidaten_04.py | 533 ------------------ 1 file changed, 533 deletions(-) delete mode 100644 Operations_Research_mit_Python_Version_04/erzeuge_stichwortkandidaten_04.py diff --git a/Operations_Research_mit_Python_Version_04/erzeuge_stichwortkandidaten_04.py b/Operations_Research_mit_Python_Version_04/erzeuge_stichwortkandidaten_04.py deleted file mode 100644 index 186c624..0000000 --- a/Operations_Research_mit_Python_Version_04/erzeuge_stichwortkandidaten_04.py +++ /dev/null @@ -1,533 +0,0 @@ -#!/usr/bin/env python3 - -# erzeuge_stichwortkandidaten_04.py -""" -Findet Fachbegriffe fuer das Stichwortregister, die NICHT im Glossar -stehen — automatisch, mit spaCy POS-Tagging, Lemmatisierung und -NER (Personennamen). Hybrid: Glossar als Kern, freie Extraktion als -Ergaenzung, zwei Stopplisten als Filter. - -Pipeline: - 1. Text aus Kapiteldateien (ohne Code/Math) extrahieren - 2. spaCy: NOUN, PROPN, ADJ + PER-Entities lemmatisiert sammeln - 3. Abkuerzungen per Regex - 4. Buchspezifische Stoppliste: die haeufigsten Woerter des Buchs, - die keine Fachbegriffe sind - 5. Frequenzfilter: 2–N Vorkommen = Kandidat, >N = Stoppwort, - 1 = nur wenn im Glossar - 6. Kandidatenliste als Vorschlag (--vorschlag) oder direkt markieren - -Aufruf (aus dem Wurzelverzeichnis Version_04): - python3 Operations_Research_mit_Python_Version_04/erzeuge_stichwortkandidaten_04.py --vorschlag - python3 .../erzeuge_stichwortkandidaten_04.py --bericht - python3 .../erzeuge_stichwortkandidaten_04.py # markieren - python3 .../erzeuge_stichwortkandidaten_04.py --check # nur melden -""" - -import argparse -import os -import re -import sys -from collections import Counter - -HIER = os.path.dirname(os.path.abspath(__file__)) -BASIS = os.path.dirname(HIER) -sys.path.insert(0, HIER) - -from glossar_eintraege_04 import EINTRAEGE # noqa: E402 -import build_version_04 as b # noqa: E402 - -SKIP_DATEIEN = {"94_Anhang_Glossar.md", "95_Anhang_Literatur.md"} - -# --- Allgemeine deutsche Stoppliste ---------------------------------------- -# Artikel, Pronomen, Konjunktionen, Praepositionen, Hilfsverben, Partikeln. -# Nicht aus einer Frequenzliste abgeleitet, sondern per Hand: diese Woerter -# sind grammatikalisch, nie fachlich. spaCy taggt sie ohnehin nicht als -# NOUN/PROPN, aber adjektivische Formen ("einfach", "gross") landen als -# ADJ im Pool und muessen hier heraus. -_ALLGEMEINE_STOPP = frozenset({ - # Artikel - "der", "die", "das", "den", "dem", "des", "ein", "eine", "einer", - "eines", "einem", "einen", "kein", "keine", "keiner", - # Pronomen - "ich", "du", "er", "sie", "es", "wir", "ihr", "mich", "dich", "sich", - "uns", "euch", "mein", "dein", "sein", "unser", "euer", "ihre", "deren", - "dieser", "diese", "dieses", "jener", "jene", "jenes", "welcher", - "welche", "welches", "wer", "was", "man", "jemand", "niemand", - # Konjunktionen / Partikeln - "und", "oder", "aber", "denn", "sondern", "weil", "wenn", "als", - "ob", "dass", "damit", "weder", "noch", "entweder", "sowohl", - "auch", "nur", "noch", "schon", "immer", "nie", "oft", "sehr", - "mehr", "meist", "viel", "wenig", "etwas", "nichts", "alles", - # Praepositionen - "in", "an", "auf", "aus", "bei", "mit", "nach", "seit", "von", "zu", - "gegen", "ohne", "um", "fuer", "ueber", "unter", "zwischen", "durch", - "wegen", "waehrend", "trotz", "innerhalb", "ausserhalb", "oberhalb", - "unterhalb", "statt", "trotz", - # Hilfsverben (als Lemma) - "sein", "haben", "werden", "koennen", "muessen", "duerfen", "sollen", - "wollen", "moegen", "tun", "machen", "geben", "nehmen", "kommen", - "gehen", "stehen", "liegen", "sitzen", - # haeufige Adjektive, die keine Fachbegriffe sind - "gut", "besser", "beste", "gross", "grosser", "klein", "neu", "alt", - "hoch", "niedrig", "lang", "kurz", "weit", "nah", "einfach", - "schwer", "leicht", "wichtig", "unwichtig", "moeglich", "unmoeglich", - "notwendig", "ueberfluessig", "bekannt", "unbekannt", "deutlich", - "klar", "unsicher", "sicher", "richtig", "falsch", "wahr", "unwahr", - "ganze", "ganzer", "ganzen", "gesamte", "saemtlich", "jed", - "jede", "jeder", "jedes", "all", "alle", "aller", "saemtliche", - # Zahlenworte - "eins", "zwei", "drei", "vier", "fuenf", "sechs", "sieben", "acht", - "neun", "zehn", "erste", "zweite", "dritte", "letzte", "naechste", - "vorige", "vorherige", "nachste", "obige", "untere", "obere", - # Sonstiges - "ja", "nein", "bitte", "danke", "eben", "ebenfalls", "zusatz", - "zusaetzlich", "weiter", "weiterer", "weitere", "ferner", - # Strukturelle Begriffe des Buchs (keine Fachbegriffe) - "handrechnung", "micro-quiz", "denkfehler", "schnellstart", - "lernziel", "aufgabe", "loesung", "lösung", "zusammenfassung", - "selbsttest", "selbstkontrolle", "wiederholung", "merkzahl", - "merksatz", "kapitel", "abschnitt", "anhang", "teil", "datei", - "dateien", "programm", "programme", "beispiel", "beispiele", - "tabelle", "abbildung", "datei", "verzeichnis", "register", - "glossar", "literatur", "quelltext", "code", "codeblock", - "notebook", "website", "pdf", "html", "markdown", "pandoc", - "latex", "python", "tool", "werkzeug", "ressource", "ressourcen", - # Alltaegliche Substantive, die in technischen Texten haeufig sind, - # aber keine Fachbegriffe - "bereich", "mittel", "produkt", "stufe", "betrieb", "buch", - "ende", "struktur", "euro", "funktion", "variablen", "variable", - "stelle", "wert", "zahl", "fall", "beispiel", "verfahren", - "ansatz", "methode", "problem", "modell", "ergebnis", - "schritt", "weg", "art", "weise", "grund", "grundlage", - "grundlagen", "teil", "rest", "menge", "anzahl", "nummer", - "seite", "platz", "ort", "zeit", "moment", "augenblick", - "beginn", "start", "mitte", "rand", "grenze", "limit", - "kopf", "fuß", "name", "bezeichnung", "titel", "label", - "text", "wort", "satz", "absatz", "zeile", "spalte", "zelle", - "feld", "raum", "flaeche", "linie", "punkt", "zeichen", - "symbol", "formel", "gleichung", "ausdruck", "term", "faktor", - "komponente", "element", "einheit", "einheiten", "objekt", - "ding", "aspekt", "thema", "gebiet", "sektor", "zone", - "umfeld", "kontext", "umgebung", "welt", "tag", "monat", - "jahr", "woche", "stunde", "minute", "sekunde", "zeitpunkt", - "zeitraum", "periode", "phase", "abschnitt", "stueck", - "anteil", "bruch", "gesamt", "summe", "differenz", - "quotient", "rate", "verhaeltnis", "quote", "merkmal", - "eigenschaft", "attribut", "besonderheit", "detail", - "bestandteil", "voraussetzung", "bedingung", "annahme", - "hypothese", "these", "behauptung", "aussage", "feststellung", - "beobachtung", "erkenntnis", "ueberlegung", "gedanke", "idee", - "konzept", "prinzip", "regel", "gesetz", "vorschrift", - "anforderung", "bedarf", "beduerfnis", "wunsch", "ziel", - "zweck", "nutzen", "vorteil", "nachteil", "gewinn", - "verlust", "ertrag", "aufwand", "kosten", "preis", "betrag", - "person", "mann", "frau", "mensch", "leute", "personen", - "mitarbeiter", "kollege", "chef", "team", "gruppe", - "mannschaft", "kreis", "abend", "morgen", "nacht", - "kalender", "uhrzeit", "datum", "land", "stadt", "dorf", - "region", "haus", "gebäude", "raum", "zimmer", "tuer", - "fenster", "wand", "decke", "boden", "geraet", - "instrument", "maschine", "motor", "rechner", "computer", - "server", "netz", "netzwerk", "verbindung", "link", "verweis", - "daten", "datensatz", "datei", "dateien", "liste", - "verzeichnis", "register", "index", "inhaltsverzeichnis", - "fußnote", "bemerkung", "notiz", "hinweis", "tipp", "rat", - "empfehlung", "warnung", "gefahr", "risiko", "fehler", - "irrtum", "frage", "antwort", "reaktion", "folge", - "konsequenz", "auswirkung", "effekt", "wirkung", "einfluss", - "aenderung", "veraenderung", "verbesserung", "erweiterung", - "ergaenzung", "erhoehung", "verringerung", "senkung", - "steigerung", "reduktion", "abnahme", "zunahme", - "wachstum", "anlage", "investition", "kapital", "geld", - "finanzen", "wirtschaft", "forschung", "wissenschaft", - "studie", "untersuchung", "experiment", "test", "versuch", - "pruefung", "abnahme", "kontrolle", "ueberwachung", - "messung", "messwert", "berechnung", "rechnung", - "kalkulation", "analyse", "betrachtung", "darstellung", - "praesentation", "ausgabe", "eingabe", "dateiname", - "dateiendung", "format", "formate", "formatierung", - "layout", "design", "stil", "klasse", "objekt", - "instanz", "methode", "parameter", "argument", - "schnipsel", "gesamt", "ende", "mitte", "anfang", - "ueberblick", "zusammenhang", "bezug", "referenz", - "quelle", "herkunft", "ursache", "grund", "anlass", - "antrag", "auftrag", "anweisung", "befehl", "kommando", - "prozess", "prozesse", "vorgang", "ablauf", "handlung", - "aktion", "schritt", "phase", "status", "stand", - "zustand", "lage", "position", "stellung", "rolle", - "funktion", "aufgabe", "zweck", "bestimmung", -}) - -# --- Konfiguration --------------------------------------------------------- -# Ein Kandidat muss in mindestens so vielen Dateien auftauchen (nicht -# Vorkommen — Dateien, sonst fluten seltene Begriffe aus einem Kapitel -# das Register). 1 reicht: ein Begriff, der nur in einem Kapitel vorkommt, -# ist ein Fachbegriff genau dort. -MIN_DATEIEN = 3 - -# Ab dieser Anzahl Vorkommen im Gesamtbuch gilt ein Wort als -# buchspezifisches Stoppwort (es ist "Alltagssprache" des Buchs, kein -# Fachbegriff). Glossarbegriffe sind davon ausgenommen. -STOPP_SCHWELLE = 15 - -# Maximale Anzahl Vorkommen fuer einen Kandidaten: ueber dieser Grenze -# ist ein Begriff zu allgemein (erscheint in fast jedem Kapitel). -MAX_VORKOMMEN = STOPP_SCHWELLE - 1 - -# Mindestlaenge eines Kandidaten-Lemmas: unter 4 Zeichen ist fast -# immer Rauschen (Artikel, Pronomen, Variablennamen wie w_1). -MIN_LAENGE = 4 - - -def _idx_marke_als_suchbegriff(marke: str) -> str: - """{idx:Branch-and-Bound!Bounding} → 'Bounding' (Unterbegriff).""" - if "!" in marke: - marke = marke.split("!", 1)[1] - if "@" in marke: - marke = marke.rsplit("@", 1)[-1] - marke = re.sub(r"\s*\([^)]*\)\s*$", "", marke) - return marke.strip() - - -def glossar_begriffe() -> set[str]: - """Alle Anzeigenamen und Indexmarken aus dem Glossar.""" - out = set() - for name, idx, _, _ in EINTRAEGE: - out.add(name) - if idx: - out.add(_idx_marke_als_suchbegriff(idx)) - out.add(idx) - return out - - -def _entferne_code_und_math(text: str) -> str: - """Entfernt Codebloecke, Inline-Code und Math aus dem Text. - - spaCy soll nur natuerlichsprachlichen Text sehen — Code enthaelt - Variablennamen, die als PROPN getaggt wuerden und das Register - fluten.""" - # Display-Math: $$...$$ (mehrzeilig) - text = re.sub(r"\$\$[\s\S]*?\$\$", " ", text) - # Inline-Math: $...$ - text = re.sub(r"\$[^$\n]+\$", " ", text) - # LaTeX-math: \(...\) und \[...\] - text = re.sub(r"\\\([\s\S]*?\\\)", " ", text) - text = re.sub(r"\\\[[\s\S]*?\\\]", " ", text) - # Codebloecke (```...```) - text = re.sub(r"```[\s\S]*?```", " ", text) - # Inline-Code: `...` - text = re.sub(r"`[^`]+`", " ", text) - # Markdown-Link-Ziele entfernen: [Text](URL) → Text - text = re.sub(r"\[([^\]]*)\]\([^)]+\)", r"\1", text) - # {idx:...}, {ref:...}, {#...} Marker entfernen - text = re.sub(r"\{(?:idx|ref|kap|sec|anhang|teil)[:#][^}]*\}", " ", text) - # Bilddarstellungen: ![alt](pfad) → alt - text = re.sub(r"!\[([^\]]*)\]\([^)]+\)", r"\1", text) - # Ueberschriften-Präfixe entfernen (# → Leerzeichen) - text = re.sub(r"^#{1,6}\s+", " ", text, flags=re.MULTILINE) - # Blockquote-Marker entfernen - text = re.sub(r"^>\s?", "", text, flags=re.MULTILINE) - # LaTeX-Befehle entfernen: \textbf, \index, \clearpage etc. - text = re.sub(r"\\[a-zA-Z]+", " ", text) - # Markdown-Tabellen-Trenner entfernen - text = re.sub(r"\|", " ", text) - return text - - -def _abkuerzungen(text: str) -> set[str]: - """Extrahiert Abkuerzungen per Regex. - - Muster: - - 2+ Grossbuchstaben: LP, MILP, CVaR, KKT, VRP, IIS - - Grossbuchstabe + Bindestrich + Grossbuchstabe: CP-SAT - - Grossbuchstabenfolge mit Zahlen: A* (nicht hier), IPv6 - """ - out = set() - # 2+ aufeinanderfolgende Grossbuchstaben (mit Bindestrichen/Zahlen) - for m in re.finditer(r"\b([A-Z][A-Z0-9]+(?:-[A-Z0-9]+)*)\b", text): - abk = m.group(1) - if len(abk) < 2: - continue - # Anhang-/Abschnittsnummern ueberspringen: B1, C2, D3, A1 etc. - # (ein Grossbuchstabe + Ziffern, kein echter Begriff) - if re.fullmatch(r"[A-Z]\d+", abk): - continue - out.add(abk) - return out - - -def verarbeite_text(nlp, text: str) -> list[tuple[str, str]]: - """Gibt Liste von (Lemma, POS-Tag) fuer Kandidaten zurueck.""" - # spaCy hat ein Limit von 1M Zeichen; wir verarbeiten in Chunks - MAX_CHARS = 900_000 - ergebnis: list[tuple[str, str]] = [] - for i in range(0, len(text), MAX_CHARS): - chunk = text[i:i + MAX_CHARS] - doc = nlp(chunk) - for token in doc: - pos = token.pos_ - if pos in ("NOUN", "PROPN"): - # ADJ bewusst nicht: konvex/linear/ganzzahlig gehoeren ins - # Glossar (mit Definition), nicht in die freie Extraktion. - # spaCy-ADJ-Tags sind zu verrauscht ("haeufig", "echt"). - lemma = token.lemma_.lower() - if not lemma or len(lemma) < MIN_LAENGE: - continue - if lemma in _ALLGEMEINE_STOPP: - continue - # Numerische/sonderzeichen-Lemmas ueberspringen - if re.fullmatch(r"[0-9\W]+", lemma): - continue - # Variablennamen: w_1, z_t, r_j, x_12 etc. - if re.fullmatch(r"[a-z]_\w+", lemma): - continue - # LaTeX-Reste: \in, \mathbf, begin, end, textbf etc. - if lemma.startswith("\\"): - continue - if lemma in ("begin", "end", "textbf", "texttt", "item", - "frac", "quad", "sum", "min", "max", "arg", - "label", "ref", "cite", "index", "printindex", - "clearpage", "newpage", "section", "subsection", - "paragraph", "center", "include", "input"): - continue - # Token darf nur Buchstaben (inkl. Umlaute) und - # Bindestriche enthalten — sonst ist es Rauschen. - if not re.fullmatch(r"[a-zäöüß-]+", lemma): - continue - ergebnis.append((lemma, pos)) - # Named Entities (PER = Personennamen) - for ent in doc.ents: - if ent.label_ == "PER": - name = ent.text.strip() - if name and len(name) >= MIN_LAENGE: - # Nur Buchstaben und Bindestriche - if re.fullmatch(r"[A-Za-zäöüÄÖÜß -]+", name): - ergebnis.append((name, "PER")) - return ergebnis - - -def main() -> int: - parser = argparse.ArgumentParser( - description="Findet Fachbegriffe fuer das Stichwortregister, die nicht " - "im Glossar stehen — mit spaCy POS-Tagging und NER.") - parser.add_argument("--vorschlag", action="store_true", - help="Kandidatenliste ausgeben, nichts markieren") - parser.add_argument("--bericht", action="store_true", - help="ausfuehrliche Liste je Datei") - parser.add_argument("--check", action="store_true", - help="nur melden, keine Dateien schreiben") - parser.add_argument("--schwelle", type=int, default=STOPP_SCHWELLE, - help=f"Stoppwort-Schwelle (Standard: {STOPP_SCHWELLE})") - args = parser.parse_args() - - import spacy - print("Lade spaCy-Modell de_core_news_md …") - nlp = spacy.load("de_core_news_md") - nlp.max_length = 2_000_000 - - # 1. Glossarbegriffe sammeln (als Quelle + Ausschlusskriterium) - g_begriffe = glossar_begriffe() - print(f"Glossarbegriffe (als Quelle): {len(g_begriffe)}") - - # 2. Text aus allen Kapiteldateien sammeln - print("Lese Kapiteldateien …") - alle_tokens: list[tuple[str, str]] = [] - abkuerzungen_all: set[str] = set() - datei_vorkommen: dict[str, set[str]] = {} # lemma → set von Dateien - vorkommen_gesamt: Counter = Counter() - - for datei in b.DATEIEN: - if datei in SKIP_DATEIEN: - continue - pfad = os.path.join(HIER, datei) - if not os.path.exists(pfad): - continue - with open(pfad, encoding="utf-8") as f: - roh = f.read() - text = _entferne_code_und_math(roh) - - # Abkuerzungen sammeln - abk = _abkuerzungen(text) - abkuerzungen_all |= abk - - # spaCy-Tokens - tokens = verarbeite_text(nlp, text) - datei_lemmas = set() - for lemma, pos in tokens: - alle_tokens.append((lemma, pos)) - datei_lemmas.add(lemma) - for lemma in datei_lemmas: - datei_vorkommen.setdefault(lemma, set()).add(datei) - vorkommen_gesamt[lemma] += 1 - - # 3. Frequenzanalyse - freq = Counter(lemma for lemma, _ in alle_tokens) - - # 4. Buchspezifische Stoppliste - buch_stopp = {lemma for lemma, count in freq.items() - if count >= args.schwelle} - # Glossarbegriffe niemals stoppen - buch_stopp -= g_begriffe - - print(f"\nBuchspezifische Stoppwoerter (>= {args.schwelle} Vorkommen): " - f"{len(buch_stopp)}") - if buch_stopp and args.bericht: - for w in sorted(buch_stopp)[:30]: - print(f" {w} ({freq[w]})") - if len(buch_stopp) > 30: - print(f" … und {len(buch_stopp) - 30} weitere") - - # 5. Abkuerzungen: Filtern — Glossarbegriffe als eigene Kategorie - abk_im_glossar = sorted(a for a in abkuerzungen_all - if a in g_begriffe) - abk_kandidaten = sorted( - a for a in abkuerzungen_all - if a not in g_begriffe - and a not in buch_stopp - and len(a) >= 2 - ) - - # 6. Kandidaten sammeln: Lemma, das nicht Stoppwort ist, - # in MIN_DATEIEN Dateien vorkommt, und nicht nur 1x insgesamt. - # Glossarbegriffe werden als eigene Kategorie gefuehrt. - kandidaten_nomen: list[tuple[str, int, int]] = [] # (lemma, freq, dateien) - nomen_im_glossar: list[tuple[str, int, int]] = [] - for lemma, count in freq.items(): - if lemma in buch_stopp: - continue - if count < 2: - continue - n_dateien = len(datei_vorkommen.get(lemma, set())) - if n_dateien < MIN_DATEIEN: - continue - if lemma in g_begriffe: - nomen_im_glossar.append((lemma, count, n_dateien)) - else: - kandidaten_nomen.append((lemma, count, n_dateien)) - - # Nach Frequenz absteigend sortieren - kandidaten_nomen.sort(key=lambda x: x[1], reverse=True) - nomen_im_glossar.sort(key=lambda x: x[1], reverse=True) - - print(f"\n=== Kandidaten ===") - print(f"Abkuerzungen (neu): {len(abk_kandidaten)}") - print(f"Abkuerzungen (Glossar): {len(abk_im_glossar)}") - print(f"Nomen (neu): {len(kandidaten_nomen)}") - print(f"Nomen (Glossar): {len(nomen_im_glossar)}") - gesamt = (len(abk_kandidaten) + len(abk_im_glossar) - + len(kandidaten_nomen) + len(nomen_im_glossar)) - print(f"Gesamt: {gesamt}") - - # 7. Ausgabe - if args.vorschlag or args.bericht: - if abk_im_glossar: - print(f"\n--- Abkuerzungen im Glossar ({len(abk_im_glossar)}) ---") - for abk in abk_im_glossar: - n_dateien = len(datei_vorkommen.get(abk.lower(), set())) - print(f" {abk:<20} ({freq.get(abk.lower(), 0)} Vorkommen, " - f"{n_dateien} Dateien) [Glossar]") - - print(f"\n--- Abkuerzungen (neue Kandidaten) ({len(abk_kandidaten)}) ---") - for abk in abk_kandidaten: - n_dateien = len(datei_vorkommen.get(abk.lower(), set())) - print(f" {abk:<20} ({freq.get(abk.lower(), 0)} Vorkommen, " - f"{n_dateien} Dateien)") - - if nomen_im_glossar: - print(f"\n--- Nomen im Glossar ({len(nomen_im_glossar)}) ---") - print(f" (Lemma | Vorkommen | Dateien)") - for lemma, count, n_dateien in nomen_im_glossar: - print(f" {lemma:<35} {count:>4} {n_dateien:>2} Dateien [Glossar]") - - print(f"\n--- Nomen (neue Kandidaten) ({len(kandidaten_nomen)}) ---") - print(f" (Lemma | Vorkommen | Dateien)") - for lemma, count, n_dateien in kandidaten_nomen: - mark = " ★" if count >= 5 else "" - print(f" {lemma:<35} {count:>4} {n_dateien:>2} Dateien{mark}") - - if args.vorschlag: - print(f"\n--vorschlag: Keine Dateien geaendert. " - f"Pruefen Sie die Liste; gewuenschte Begriffe im Glossar " - f"ergaenzen oder direkt mit --check/--bericht markieren.") - return 0 - - # 8. Markieren (nur in --check oder Default) - # Glossarbegriffe sind bereits durch erzeuge_stichwortregister_04.py - # markiert — sie werden hier NICHT erneut eingefuegt. - # Nur neue Kandidaten (Abkuerzungen + Nomen) werden markiert. - if args.check: - print(f"\n--check: {len(abk_kandidaten) + len(kandidaten_nomen)} " - f"neue Kandidaten wuerden markiert werden " - f"(Glossarbegriffe ausgenommen).") - return 0 - - # Tatsaechliches Markieren — nur neue Kandidaten - alle_kandidaten = ( - [(abk, abk) for abk in abk_kandidaten] - + [(lemma, lemma) for lemma, _, _ in kandidaten_nomen] - ) - alle_kandidaten.sort(key=lambda x: len(x[0]), reverse=True) - - gesamt_markiert = 0 - for datei in b.DATEIEN: - if datei in SKIP_DATEIEN: - continue - pfad = os.path.join(HIER, datei) - if not os.path.exists(pfad): - continue - with open(pfad, encoding="utf-8") as f: - text = f.read() - - einfuegungen: list[tuple[int, str, str]] = [] - belegt: list[tuple[int, int]] = [] - - for suchbegriff, indexmarke in alle_kandidaten: - # Wortgrenzen fuer deutschen Text - muster = re.compile( - r"(?