Weiche Trennstriche auflösen, Courier-OCR-Ebenen nicht als Code setzen

- Zeilenende mit U+00AD oder "¬" wird wie Silbentrennung behandelt
  ("wach­ senden" -> "wachsenden")
- Unsichtbarer Text (OCR-Ebene) verliert das Monospace-Flag, sonst setzt
  pymupdf4llm jedes Wort in Backticks
- Tests für beide Fälle und für sichtbaren Monospace-Text

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-02 13:51:50 +02:00
commit 217d1ee09b

View file

@ -472,28 +472,39 @@ def load_outline(doc: pymupdf.Document) -> dict[str, int]:
# ===========================================================================
# Korrektur für pymupdf4llm: Bindestrich-Komposita am Zeilenende
# Korrektur für pymupdf4llm: Trennstriche am Zeilenende, OCR-Ebenen
# ===========================================================================
# pymupdf4llm entfernt jeden Bindestrich am Zeilenende ("Militär-" + Zeile
# "Geheimdienst" -> "MilitärGeheimdienst"). Für Großbuchstaben und
# Konjunktionen ("Arbeits- und") markieren wir den Strich vorher, sodass er
# erhalten bleibt. Echte Silbentrennung (Kleinbuchstabe) bleibt unverändert.
# Weiche Trennstriche (U+00AD) und "¬" kennt pymupdf4llm nicht ("wach­ senden");
# sie trennen immer innerhalb eines Wortes und werden zu "-", das dann entfällt.
#
# Unsichtbarer Text (OCR-Ebene eines Scans) ist oft in Courier gesetzt;
# pymupdf4llm hielte ihn sonst für Programmcode und setzte jedes Wort in `…`.
KEEP_HYPHEN = "\ue000" # Strich behalten, ohne Leerzeichen anschließen
KEEP_HYPHEN_SPACE = "\ue001" # Strich und Leerzeichen behalten
SOFT_HYPHENS = ("\u00ad", "¬")
MONOSPACE_FLAG = 8
def _mark_line_end_hyphens(spans: list[dict]) -> list[dict]:
marked = []
for i, span in enumerate(spans):
nxt = spans[i + 1] if i + 1 < len(spans) else None
if not span.get("char_flags", VISIBLE_TEXT) & VISIBLE_TEXT:
span = {**span, "flags": span.get("flags", 0) & ~MONOSPACE_FLAG}
text = span["text"].rstrip()
if (
nxt is not None
and text.endswith("-")
and (span.get("block"), span.get("line"))
!= (nxt.get("block"), nxt.get("line"))
):
line_end = nxt is not None and (span.get("block"), span.get("line")) != (
nxt.get("block"), nxt.get("line")
)
if line_end and text.endswith(SOFT_HYPHENS):
span = {**span, "text": text[:-1] + "-"}
elif line_end and text.endswith("-"):
word = FIRST_WORD.match(nxt["text"].lstrip())
if word and word.group(0).lower() in CONJUNCTIONS:
span = {**span, "text": text + KEEP_HYPHEN_SPACE}