From 43e91612875de3cc6e7466eee56023ab55cefd89 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Fri, 24 Jul 2026 22:29:35 +0200 Subject: Add Lower Saxony NEFG acceptance case and two parser robustness fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second §-structured Landesrecht case for wave six: the Lower Saxony ELER Support Act (NEFG, unchanged since 2022, derived from the two-column Nds. GVBl 2022 No. 33) plus the amending act of 28 Jan 2026 (Nds. GVBl 2026 No. 10). Five of seven commands apply — both "erhält folgende Fassung" re-enactments (§ 1(1), § 2), the citation replacement in § 1(5), the words insertion in § 6(1), and the § 13 → § 14 renumbering. - LandesRechtTextParser: a norm head no longer accepts a title ending in a full stop, so a cross-reference sentence at line start ("§ 7 GAPInVeKoSG findet entsprechend Anwendung.") is not misread as a norm head "§ 7" (which had made the monotonicity check swallow the norms in between). - TextBereiniger: strip the Lower Saxony GVBl running footer and publisher line. The footer sat between two enumerated items and otherwise attached to the preceding re-enactment quote, defeating its end-of-sentence anchor. - Add sampledata/Niedersachsen/NEFG-alt.txt and EndToEndTest.nefgAcceptance. Two insertion forms remain documented residues (manuell prüfen): inserting a §-block with a space-separated sub-number ("§ 2 a") and a chapter-scoped §-block insertion ("In Kapitel 4 wird nach § 12 … angefügt"). 221 tests green; federal, Bavarian and Saxon pinned numbers unchanged. Co-Authored-By: Claude Opus 4.8 Change-Id: Ie23eee1f596ec8eecc6a73f6ce585a22e73ec6c9 --- .../eu/mulk/aendggner/aenderung/parse/TextBereiniger.java | 12 +++++++++++- .../eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java | 5 ++++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/eu/mulk/aendggner/aenderung/parse/TextBereiniger.java b/src/main/java/eu/mulk/aendggner/aenderung/parse/TextBereiniger.java index d79df60..9c1edaa 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/parse/TextBereiniger.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/TextBereiniger.java @@ -123,6 +123,14 @@ public final class TextBereiniger { Pattern.compile( "^\\s*https?://\\S+\\s+Fassung vom \\d{1,2}\\.\\d{1,2}\\.\\d{4}\\s+Seite \\d+ von \\d+\\s*$"); + // Niedersächsisches GVBl: laufende Fußzeile („Nds. GVBl. 2026 Nr. 10 vom 4. Februar 2026 Seite 2“) + // und Herausgeberzeile. Die Fußzeile steht zwischen zwei Aufzählungsgliedern und hängte sich sonst + // an den vorangehenden Befehl (Neufassungs-Zitat), sodass dessen Satzende-Anker nicht mehr greift. + private static final Pattern NDS_GVBL_FUSS = + Pattern.compile("^\\s*Nds\\. GVBl\\. \\d{4} Nr\\. \\d+ vom .+? Seite \\d+\\s*$"); + private static final Pattern NDS_HERAUSGEBER = + Pattern.compile("^\\s*Herausgeber: Niedersächsische Staatskanzlei\\s*$"); + /** Konjunktionen, die typischerweise auf einen Suspensivstrich folgen („Wirk- und …“). */ private static final Pattern KONJUNKTION = Pattern.compile("^(und|oder|sowie|bzw\\.|beziehungsweise)\\b.*"); @@ -292,7 +300,9 @@ public final class TextBereiniger { || LANDTAG_SEITENKOPF.matcher(zeile).matches() || LANDTAG_TITELKOPF.matcher(zeile).matches() || LANDTAG_MARKE.matcher(zeile).matches() - || REVOSAX_FUSS.matcher(zeile).matches(); + || REVOSAX_FUSS.matcher(zeile).matches() + || NDS_GVBL_FUSS.matcher(zeile).matches() + || NDS_HERAUSGEBER.matcher(zeile).matches(); } /** diff --git a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java index 23260de..ada273c 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java @@ -69,7 +69,10 @@ final class LandesRechtTextParser { // dass „Satz“ auch „Satzungen“, „Nummer“ auch „Nummerierung“ trifft. + "(?!(?:Absatz|Abs\\.|Satz|Sätze|Nummer|Nr\\.|Buchstabe|Buchst\\." + "|und|bis|oder|sowie|des|der|dieses)(?![a-zäöüß]))" - + "((?:\\p{Lu}|\\().*)$"); + // Der Titel endet nicht auf einen Punkt: ein Normkopf trägt eine Überschrift, keinen + // ganzen Satz. So wird ein am Zeilenanfang stehender Querverweis-Satz („§ 7 GAPInVeKoSG + // findet entsprechend Anwendung.“) nicht fälschlich als Normkopf „§ 7“ gelesen. + + "((?:\\p{Lu}|\\().*[^.])\\s*$"); private static final Pattern WEGGEFALLEN_TITEL = Pattern.compile("^\\((?:aufgehoben|weggefallen)\\)$"); -- cgit v1.2.1