diff options
| author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2026-08-23 16:00:25 +0200 |
|---|---|---|
| committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2026-08-23 16:00:25 +0200 |
| commit | 5203e9407979dbb920bc796ee457ce7c12911ef9 (patch) | |
| tree | c2a51745e1e3ca31feb3f8daf8b4a7533fa98ed1 /src/main/java | |
| parent | fa6a5491cac88e1529454572c900bfa19b8c9fbe (diff) | |
Die Anlage wird eine Norm, ihre Nummern noch nicht
Der Klartext-Parser trägt fortan Anlagen: „Anlage“, „Anlage 2“ und „Anhang“
eröffnen eine eigene Norm, deren Bezeichnung genau so lautet wie im gii-XML, und
vom ersten Anlagenkopf an gehört alles Folgende zu ihr — ihre inneren
Überschriften gliedern nicht mehr das Gesetz, und ein Paragraph, den sie
zitieren, eröffnet keine Norm.
Berlin ist damit zur Hälfte belegt. Artikel 2 des Änderungsgesetzes schreibt das
LAF-Errichtungsgesetz vollständig fort; alle fünf Normen gleichen danach der
amtlichen Fassung vom 12. Juni 2026. Artikel 1 bleibt bei der Erkennung, und der
Grund ist benannt statt umgangen: Fünf seiner sechs Befehle zielen auf Einheiten
der Anlage, die dort als Überschriften stehen — „Nummer 6“, „Nummer 23“,
„Nummer 31“ —, während der Stellenauflöser eine Aufzählungsmarke „6.“ sucht, die
im Text der Anlage vielfach vorkommt. Die Gegenprobe belegt es: Werden die
Überschriften versuchsweise in Marken umgeschrieben, steigt die Zahl der
angewandten Befehle von zwei auf drei, mehrdeutig bleibt der Rest. Die Nummern
einer Anlage brauchen einen eigenen Rang zwischen Norm und Absatz.
Solange er fehlt, bringt die Beilage von zweimal 380 kB Stammfassung keinen
Prüfgewinn; ihr Bezugsweg steht in „Berlin/SOURCES“ und führt in zwei Abrufen
wieder dorthin. Dort ist auch der zweite Berliner Befund festgehalten: Das Portal
setzt die amtlichen Satznummern als angeklebte Ziffern statt als Superskripte.
Geprüft durch „mvnw verify“: 328 Tests, keine bestehende gepinnte Zahl bewegt,
REUSE-Konformität 165 von 165.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ifdda599a8c641ce66d0370b2a027f556adb4d86d
Diffstat (limited to 'src/main/java')
| -rw-r--r-- | src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java | 38 |
1 files changed, 33 insertions, 5 deletions
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 7976cd9..d6a1d2e 100644 --- a/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java +++ b/src/main/java/eu/mulk/aendggner/gesetz/land/LandesRechtTextParser.java @@ -92,6 +92,15 @@ final class LandesRechtTextParser { */ private static final String INHALTSUEBERSICHT = "Inhaltsübersicht"; + /** + * Normkopf einer Anlage oder eines Anhangs, nummeriert („Anlage 2“) wie unnummeriert-benannt + * („Anlage“). Die enbez lautet genau so, wie das gii-XML sie führt, damit {@link + * eu.mulk.aendggner.aenderung.Stelle#anlagenEnbez()} sie unverändert trifft. Ein etwaiger Titel + * folgt auf eigenen Zeilen und geht in den Normtitel ein. + */ + private static final Pattern ANLAGEN_KOPF = + Pattern.compile("^(Anlage|Anhang)(?:\\s+(\\d+[a-z]?))?\\s*$"); + // Normkopf: „§ N“ bzw. „Art. N“ plus Titel auf derselben Zeile. Das Sigel steht in Gruppe 1, die // Nummer in Gruppe 2, der Titel in Gruppe 3. Die Negativliste schließt Querverweise am // Zeilenanfang aus („Art. 4 Abs. 3 …“, „§ 5 Absatz 2 …“). @@ -164,6 +173,11 @@ final class LandesRechtTextParser { String elternKennzahl = null; int gliederungsZaehler = 0; + // Ab dem ersten Anlagen-Normkopf ist alles Folgende Inhalt der Anlagen: Ihre inneren + // Überschriften („Erster Abschnitt“, „Nummer 6“) gliedern nicht das Gesetz, und ein Paragraph, + // der in ihnen zitiert wird, eröffnet keine Norm. Nur eine weitere Anlage tut das. + boolean imAnlagenteil = false; + String normEnbez = null; String normTitel = null; var normZeilen = new ArrayList<String>(); @@ -178,6 +192,7 @@ final class LandesRechtTextParser { var roemisch = zeile != null ? GLIEDERUNG_ROEMISCH.matcher(zeile) : null; var unterGliederung = zeile != null ? UNTER_GLIEDERUNG.matcher(zeile) : null; var normKopf = zeile != null ? NORM_KOPF.matcher(zeile) : null; + var anlagenKopf = zeile != null ? ANLAGEN_KOPF.matcher(zeile) : null; var uebersicht = INHALTSUEBERSICHT.equals(zeile); // Die Inhaltsübersicht führt die Gliederungs-Überschriften des Gesetzes als eigene Zeilen mit // („Abschnitt 1 Allgemeine Vorschriften“). Innerhalb ihrer beendet eine solche Zeile die Norm @@ -185,6 +200,7 @@ final class LandesRechtTextParser { // verloren. var gliederungsZeile = zeile != null + && !imAnlagenteil && (gliederung.matches() || arabisch.matches() || ordinalwort.matches() @@ -192,10 +208,14 @@ final class LandesRechtTextParser { || (unterGliederung.matches() && istUnterGliederung(unterGliederung, zeilen, i))) && (!INHALTSUEBERSICHT.equals(normEnbez) || folgtNormkopf(zeilen, i)); - if (zeile == null - || uebersicht - || gliederungsZeile - || (normKopf.matches() && istNeuerNormKopf(normKopf.group(2), letzteNormNummer))) { + boolean neueNorm = + zeile != null + && !imAnlagenteil + && normKopf.matches() + && istNeuerNormKopf(normKopf.group(2), letzteNormNummer); + boolean neueAnlage = zeile != null && anlagenKopf.matches(); + + if (zeile == null || uebersicht || gliederungsZeile || neueNorm || neueAnlage) { // Laufende Norm abschließen. if (normEnbez != null) { normen.add(baueNorm(normEnbez, normTitel, aktuelleGliederung, normZeilen)); @@ -239,7 +259,15 @@ final class LandesRechtTextParser { ordinalwort.group(1) + " " + ordinalwort.group(2), titel.isEmpty() ? null : titel); gliederungen.add(aktuelleGliederung); - } else if (normKopf.matches() && istNeuerNormKopf(normKopf.group(2), letzteNormNummer)) { + } else if (neueAnlage) { + imAnlagenteil = true; + normEnbez = + anlagenKopf.group(2) == null + ? anlagenKopf.group(1) + : anlagenKopf.group(1) + " " + anlagenKopf.group(2); + normTitel = null; + aktuelleGliederung = null; + } else if (neueNorm) { normEnbez = normKopf.group(1) + " " + normKopf.group(2); normTitel = normKopf.group(3) != null ? normKopf.group(3).strip() : null; letzteNormNummer = numerisch(normKopf.group(2)); |
