diff --git a/functions/verfahrensgebiet_shape_komplett.py b/functions/verfahrensgebiet_shape_komplett.py index 1a88860..a3791b1 100644 --- a/functions/verfahrensgebiet_shape_komplett.py +++ b/functions/verfahrensgebiet_shape_komplett.py @@ -42,6 +42,7 @@ oder kein Ergebnis liefert, bricht den Workflow ab. from __future__ import annotations import os +import re import shutil import tempfile import zipfile @@ -106,6 +107,57 @@ _GEBIETSTYP_LAYER_NAMEN = { # Interne Hilfsfunktionen # --------------------------------------------------------------------------- +def _normalisiere_feldname(name: str) -> str: + """Normalisiert einen Feldnamen für den toleranten Vergleich. + + Entfernt alle Zeichen außer Buchstaben/Ziffern (z.B. Punkte, Leerzeichen, + Unterstriche) und wandelt in Kleinbuchstaben um. Hintergrund: manche + Shape-Exporte liefern den Feldnamen ``FBSchl`` mit einem angehängten + Punkt (``FBSchl.``) oder abweichender Groß-/Kleinschreibung, wodurch ein + exakter Namensvergleich das Feld fälschlich als fehlend meldet (#44). + + Parameters + ---------- + name : + Roher Feldname. + + Returns + ------- + str + Normalisierter Feldname (nur Kleinbuchstaben/Ziffern). + """ + return re.sub(r"[^a-zA-Z0-9]", "", name).lower() + + +def _finde_fbschl_index(raw_layer) -> int: + """Sucht den Feldindex von ``FBSchl`` tolerant gegenüber Abweichungen im + Namen (Groß-/Kleinschreibung, angehängte Sonderzeichen wie ein Punkt). + + Versucht zuerst den exakten Namen; schlägt das fehl, wird über alle + Felder mit normalisiertem Namensvergleich gesucht (siehe + :func:`_normalisiere_feldname`). + + Parameters + ---------- + raw_layer : + Dateibasierter Shapefile-Layer. + + Returns + ------- + int + Feldindex, oder ``-1`` wenn kein passendes Feld gefunden wurde. + """ + idx = raw_layer.fields().indexFromName(FBSCHL_FELD) + if idx >= 0: + return idx + + ziel = _normalisiere_feldname(FBSCHL_FELD) + for feld_idx, feld in enumerate(raw_layer.fields()): + if _normalisiere_feldname(feld.name()) == ziel: + return feld_idx + return -1 + + def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[str]]: """Prüft das Feld ``FBSchl`` und ermittelt den Gebietstyp. @@ -113,6 +165,10 @@ def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[ zurück, damit der Aufrufer Fehler mehrerer Dateien sammeln und am Ende gemeinsam anzeigen kann. + Die Feldsuche ist tolerant gegenüber Abweichungen im Namen (z.B. ein + angehängter Punkt ``FBSchl.`` in manchen Shape-Exporten, siehe #44) – + siehe :func:`_finde_fbschl_index`. + Parameters ---------- raw_layer : @@ -127,7 +183,7 @@ def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[ ``fehlertext`` beschreibt die Ursache (fehlendes Feld oder unbekannter Wert). """ - idx = raw_layer.fields().indexFromName(FBSCHL_FELD) + idx = _finde_fbschl_index(raw_layer) if idx < 0: return None, f"Feld '{FBSCHL_FELD}' fehlt (Shape entspricht nicht dem erwarteten Inhalt)."