Markenerkennung: Grenzen gemessen, Summenzeile im Kopf ist keine Marke

Auf die Frage, ob Belege einheitlich gestaltet sind: nein. Die Erkennung
haengt an drei Annahmen - Marke in den ersten acht Zeilen, Marke in der
festen Liste, Marke ueberhaupt vorhanden. Alle drei sind jetzt gemessen und
in Tests festgehalten.

Dabei ein echter Defekt gefunden: "Total" ist Kopfmarke UND Summenwort. Ein
Beleg mit Betrag in den ersten acht Zeilen lieferte faelschlich die Marke
"Total" (an einem echten Beleg reproduziert). _betragszeile() filtert
Summenzeilen jetzt aus dem Kopf - verlangt werden beide Kennzeichen zugleich,
Summenwort und Geldangabe, damit "SHELL TANKSTELLE, 6450 SOELDEN" nicht
mitfaellt. Gegenprobe: ein echter "TOTAL TANKSTELLE"-Kopf ergibt weiter Total.

Der Ausfall beschaedigt nichts: mit unbekannter Marke im Kopf bleiben Liter,
Betrag, Rabatt und Anschrift unveraendert richtig, nur die Marke fehlt.

Parser-Suite 17 Tests (von 11), alle zwoelf abgelegten Belege liefern weiter
Shell, audi_ha_test auf 2026.9.4.22 ohne Traceback.
This commit is contained in:
2026-09-04 17:09:12 +02:00
parent bdbdb4a010
commit 8557bfe230
7 changed files with 204 additions and 5 deletions
@@ -1 +1 @@
{"version":"2026.9.4.21","sha256":"3601a55ee4120c8508dd8f5018dcfbe806f10d87fd706763a0bbd97377d217d1","bytes":323037,"gebaut":"2026-09-04T14:55:41Z"}
{"version":"2026.9.4.22","sha256":"66406934fb50aa810ff782ce877bc82d25ec8d338979d5ae9e28e5dc5c2ea521","bytes":323041,"gebaut":"2026-09-04T15:08:22Z"}
@@ -1,7 +1,7 @@
{
"domain": "audi_dashboard",
"name": "Audi Dashboard",
"version": "2026.9.4.21",
"version": "2026.9.4.22",
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
"codeowners": [
@@ -113,12 +113,40 @@ _MARKEN = (
_STRASSE_WOERTER = r"(?:stra(?:ss|ß)e|str\.|gasse|weg|platz|allee|ring|damm|chaussee)"
def _betragszeile(zeile):
"""Eine Summenzeile ("GESAMT 78,78 EUR")? Sie darf im Kopf nicht nach
Marken durchsucht werden.
Grund: "Total" ist beides - eine Kopfmarke und ein Summenwort. Auf einem
Beleg mit knappem Kopf, der den Betrag schon in den ersten acht Zeilen
druckt, wuerde daraus faelschlich die Marke "Total" (am 04.09.2026 an einem
echten Beleg mit vorangestellter Summenzeile nachgestellt und
reproduziert). Verlangt werden beide Kennzeichen ZUGLEICH - Summenwort UND
echte Geldangabe -, damit eine Anschrift mit Hausnummer oder eine
Postleitzahl ("SHELL TANKSTELLE, 6450 SÖLDEN") nicht mitfaellt."""
kompakt = re.sub(r"\s+", "", zeile).upper()
if not any(wort in kompakt for wort in _GESAMT_WOERTER):
return False
return bool(re.search(_GELD, zeile))
def _marke(zeilen):
"""Markenname aus dem Belegkopf ("SHELL STATION" -> "Shell"). None, wenn
keine bekannte Marke draufsteht - dann bleibt es beim Betreibernamen."""
kopf = "\n".join(zeilen[:8])
keine bekannte Marke draufsteht - dann bleibt es beim Betreibernamen.
Acht Zeilen, weil die Marke in allen zwoelf abgelegten Belegen in Zeile 0
steht, im oesterreichischen Format in Zeile 1 (am 04.09.2026 gemessen).
Das Fenster ist der Puffer, nicht die Erwartung.
KEINE GARANTIE, UND DAS IST ABSICHT: Belege sind nicht genormt. Steht die
Marke woanders, heisst sie anders oder fuehrt die Station gar keine (freie
Tankstellen), gibt es hier None - und der Beleg wird trotzdem vollstaendig
eingelesen, nur eben ohne Marke. Ein falscher Name waere schlimmer als
keiner."""
kopf = [z for z in zeilen[:8] if not _betragszeile(z)]
text = "\n".join(kopf)
for marke in _MARKEN:
if re.search(r"\b" + re.escape(marke) + r"\b", kopf, re.IGNORECASE):
if re.search(r"\b" + re.escape(marke) + r"\b", text, re.IGNORECASE):
return marke
return None