diff options
| author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2026-08-25 22:49:04 +0200 |
|---|---|---|
| committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2026-08-25 22:49:04 +0200 |
| commit | 20d8b08492bea77f42d019af5db66ef184f105b3 (patch) | |
| tree | b91b5dfbd39711a5f9d4e0a261869457aafdeacd /src | |
| parent | ff8e9837f11a1488dbcdf95fa47457ef74f864bb (diff) | |
Rheinland-Pfalz kennt den Strichpunkt und die Einleitung
Von den drei benannten Idiom-Grenzen des rheinland-pfälzischen Falles fallen zwei.
Die erste: „In Satz 2 wird der Punkt durch einen Strichpunkt ersetzt und
folgender Halbsatz angefügt: „…““. Zwei Neuerungen in einem Satz. „Strichpunkt“
ist die deutsche Nebenform des Semikolons und tritt zu den Satzzeichen-Mustern
hinzu — als Subjekt wie als Ziel, ohne eine einzige neue Gruppe, damit die
hartkodierten Gruppennummern des Erkenners unberührt bleiben. Der Halbsatz wird
eine eigene Ebene der Anfügung. Er beginnt keinen neuen Satz, sondern setzt den
bestehenden hinter dem Strichpunkt fort; angefügt wird er deshalb nur, wenn der
Zieltext tatsächlich auf einen Strichpunkt endet. Sonst stünde er hinter einem
Punkt und wäre gerade kein Halbsatz. Als Ziel einer Struktur-Einfügung oder
-Ersetzung bleibt er ausgeschlossen: Welche Hälfte eines Satzes gemeint wäre,
sagt keine Bezeichnung. Die Verbundmechanik selbst brauchte keinen Eingriff.
Die zweite: „In der Einleitung werden die Worte „…“ durch die Angabe „…“
ersetzt.“ Das ist ein Chapeau-Lokator wie „im Satzteil vor Nummer 1“, nur ohne
Bezugspunkt; er tritt als zweite Alternative zum vorhandenen Muster. Eine echte
Verengung auf den Satzteil vor der ersten Marke wäre eine eigene
Stellenkomponente und ist es nicht: Kommt der Zieltext außer im Chapeau auch in
einer Nummer vor, so meldet die Auflösung Mehrdeutigkeit — der richtige Ausgang.
Dass beide Befehle am rheinland-pfälzischen Stamm gleichwohl nicht greifen, liegt
an der Quelle und nicht am Werkzeug: Das Portal führt keine früheren
Gesamtausgaben, der Stamm ist hier die Nachfassung, und ihr Wortlaut trägt die
Änderung bereits.
Offen bleibt die dritte Grenze, die Verweisung auf einen anderen Punkt desselben
Artikels.
Geprüft: 386 Tests (zuvor 381).
Change-Id: I993d8645fba1c933ad8497ca175cef265df2c0b0
Diffstat (limited to 'src')
8 files changed, 212 insertions, 23 deletions
diff --git a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java index a80e09a..47bca25 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java @@ -22,6 +22,8 @@ public sealed interface Aenderungsbefehl { PARAGRAPH, ABSATZ, SATZ, + /** Die Hälfte eines am Strichpunkt geteilten Satzes; sie beginnt keinen neuen Satz. */ + HALBSATZ, NUMMER, BUCHSTABE } diff --git a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java index c825a64..ef49b7b 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java @@ -180,7 +180,7 @@ final class BefehlErkenner { // ersetzt: „…““ — der Ersatz steht als Zitatblock hinter dem Doppelpunkt. private static final Pattern PUNKT_DURCH_WORTLAUT = Pattern.compile( - "^(?:In )?(.+?) (?:wird|werden) (der Punkt|das Komma|das Semikolon)" + "^(?:In )?(.+?) (?:wird|werden) (der Punkt|das Komma|das Semikolon|der Strichpunkt)" + " am Ende(?: des Satzes)? durch " + "(?:die |den )?folgende[n]? (?:Wörter|Wortlaut) ersetzt: " + Z @@ -194,12 +194,12 @@ final class BefehlErkenner { // prüft, statt es an das Einheitsende zu heften. private static final Pattern SATZZEICHEN_ERSETZUNG_OHNE_STELLE = Pattern.compile( - "^(Der Punkt|Das Komma|Das Semikolon)(?: am Ende(?: des Satzes)?)? wird durch " + "^(Der Punkt|Das Komma|Das Semikolon|Der Strichpunkt)(?: am Ende(?: des Satzes)?)? wird durch " + "(ein Komma und " + WOERTER + " " + Z - + "|ein Komma|einen Punkt|ein Semikolon|" + + "|ein Komma|einen Punkt|ein Semikolon|einen Strichpunkt|" + WOERTER + " " + Z @@ -209,13 +209,13 @@ final class BefehlErkenner { // „am Ende“ ist wie oben entbehrlich. private static final Pattern SATZZEICHEN_ERSETZUNG = Pattern.compile( - "^(?:In )?(.+?) (?:wird|werden) (der Punkt|das Komma|das Semikolon)" + "^(?:In )?(.+?) (?:wird|werden) (der Punkt|das Komma|das Semikolon|der Strichpunkt)" + "(?: am Ende(?: des Satzes)?)? durch " + "(ein Komma und " + WOERTER + " " + Z - + "|ein Komma|einen Punkt|ein Semikolon|" + + "|ein Komma|einen Punkt|ein Semikolon|einen Strichpunkt|" + WOERTER + " " + Z @@ -473,7 +473,7 @@ final class BefehlErkenner { + WOERTER + " " + Z - + "(?: am Ende)? durch (ein Komma|ein Semikolon|einen Punkt) ersetzt\\.$"); + + "(?: am Ende)? durch (ein Komma|ein Semikolon|einen Strichpunkt|einen Punkt) ersetzt\\.$"); // „In Satz 2 wird nach dem Wort «1» ein Komma und werden die Wörter «2» eingefügt.“ private static final Pattern KOMMA_UND_WOERTER_EINFUEGUNG = @@ -518,6 +518,8 @@ final class BefehlErkenner { + Z + "\\.?$"); + private static final Pattern HALBSATZ = Pattern.compile("Halbsatz(?: \\d+[a-z]?)?"); + private static final Pattern EBENE_BEZEICHNUNG = Pattern.compile( "^(?:(?:§|Art\\.) (\\d+[a-z]?)|(?:Absatz|Abs\\.) (\\d+[a-z]?)|Satz(?: (\\d+[a-z]?))?|Sätze" @@ -583,7 +585,7 @@ final class BefehlErkenner { + WOERTER + " " + Z - + "|(ein Komma|ein Semikolon))$"); + + "|(ein Komma|ein Semikolon|einen Strichpunkt))$"); // „… ein Komma eingefügt und werden …“: Trennstellen eines Verbundbefehls sind „ und “ (ggf. mit // Komma) bzw. „, “ direkt vor „wird/werden“. Innerhalb von Zitaten steht „ und “ als «n» @@ -597,7 +599,7 @@ final class BefehlErkenner { + "|, (?=(?:die (?:Wörter|Worte)|das Wort|die Angabe|die Zahl) «)" // Ebenso vor einer Satzzeichen-Klausel („… ersetzt, der Punkt am Ende durch ein // Semikolon ersetzt und …“). - + "|, (?=(?:der Punkt|das Komma|das Semikolon) am Ende)"); + + "|, (?=(?:der Punkt|das Komma|das Semikolon|der Strichpunkt) am Ende)"); private static final Pattern WIRD_WERDEN = Pattern.compile(" (?:wird|werden) "); // Rechte Verbundklausel, die ihre Fundstelle als Struktureinheit nennt („in Satz 1 wird …“, @@ -622,7 +624,7 @@ final class BefehlErkenner { "^(?:In )?(.+?) (?:wird|werden) (?:jeweils )?(nach|vor) " + "(?:dem Wort|den (?:Wörtern|Worten)|der Angabe|der Zahl|der Verweisung) " + Z - + " (ein Komma|ein Semikolon|einen Punkt) eingefügt\\.$"); + + " (ein Komma|ein Semikolon|einen Strichpunkt|einen Punkt) eingefügt\\.$"); // „Nach der Angabe «1» wird die Angabe «2» eingefügt.“ — Anker zuerst, ohne eigene Stelle (nutzt // den Kontext). Tritt vor allem als rechte Klausel eines Verbundbefehls auf. @@ -634,7 +636,7 @@ final class BefehlErkenner { + WOERTER + " " + Z - + "|(ein Komma|ein Semikolon)) eingefügt\\.$"); + + "|(ein Komma|ein Semikolon|einen Strichpunkt)) eingefügt\\.$"); private BefehlErkenner() {} @@ -1646,7 +1648,7 @@ final class BefehlErkenner { // Klausel, deren Subjekt ein Satzzeichen ist („das Komma wird durch … ersetzt“). private static final Pattern SATZZEICHEN_SUBJEKT = - Pattern.compile("(?i)(?:der Punkt|das Komma|das Semikolon)\\b"); + Pattern.compile("(?i)(?:der Punkt|das Komma|das Semikolon|der Strichpunkt)\\b"); private static Optional<Aenderungsbefehl> erkenneVerbund( String text, Stelle kontext, ZitatExtraktor.Ergebnis zitate, Provenienz provenienz) { @@ -2032,6 +2034,11 @@ final class BefehlErkenner { private record EbeneBezeichnung(Ebene ebene, String bezeichnung) {} private static Optional<EbeneBezeichnung> ebeneUndBezeichnung(String phrase) { + // Der Halbsatz steht außerhalb des Musters, damit dessen Gruppennummern unberührt bleiben; + // eine Bezeichnung führt er nicht, denn angefügt wird stets hinter dem Strichpunkt. + if (HALBSATZ.matcher(phrase.strip()).matches()) { + return Optional.of(new EbeneBezeichnung(Ebene.HALBSATZ, null)); + } var m = EBENE_BEZEICHNUNG.matcher(phrase.strip()); if (!m.matches()) { return Optional.empty(); @@ -2280,6 +2287,7 @@ final class BefehlErkenner { case PARAGRAPH -> new Stelle.Paragraph(nummer); case ABSATZ -> new Stelle.AbsatzNr(nummer); case SATZ -> new Stelle.SatzNr(nummer); + case HALBSATZ -> new Stelle.HalbsatzNr(nummer); case NUMMER -> new Stelle.NummerNr(nummer); case BUCHSTABE -> new Stelle.BuchstabeNr(nummer); }; @@ -2366,7 +2374,8 @@ final class BefehlErkenner { return switch (Character.toLowerCase(phrase.charAt(0)) + phrase.substring(1)) { case "der Punkt", "einen Punkt" -> "."; case "das Komma", "ein Komma" -> ","; - case "das Semikolon", "ein Semikolon" -> ";"; + // „Strichpunkt“ ist die deutsche Nebenform des Semikolons; Rheinland-Pfalz schreibt sie. + case "das Semikolon", "ein Semikolon", "der Strichpunkt", "einen Strichpunkt" -> ";"; default -> throw new IllegalArgumentException("Unbekanntes Satzzeichen: " + phrase); }; } diff --git a/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java b/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java index 9176f89..466adfe 100644 --- a/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java +++ b/src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java @@ -54,10 +54,18 @@ public final class StellenParser { // „in dem Satzteil vor Nummer 1“, „in der Angabe vor Nummer 1“, bayerisch auch „Satzteil nach // Nr. 3“ — verfeinernde Chapeau-Angaben ohne eigene Stelle-Komponente; die Ersetzung sucht // ohnehin im Text der umgebenden Stelle. + // + // Die zweite Alternative nennt keinen Bezugspunkt: „In der Einleitung“ (Rheinland-Pfalz) meint + // dasselbe wie „im Satzteil vor Nummer 1“, nämlich den Chapeau des Satzes, den der Rahmen + // bezeichnet. Auch sie trägt keine eigene Komponente. Kommt der Zieltext außer im Chapeau auch + // in einer Nummer vor, so meldet die Auflösung Mehrdeutigkeit — der richtige Ausgang; eine + // echte Verengung auf den Satzteil vor der ersten Marke wäre eine eigene Komponente und gehört + // nicht hierher. private static final Pattern CHAPEAU_QUALIFIER = Pattern.compile( - "(?i)(?:im |in dem |in der |dem |der )?(?:Satzteil|Angabe) (?:vor|nach) " - + "(?:Nummer|Nr\\.|Buchstabe|Buchst\\.|Satz|Absatz|Abs\\.) \\S+"); + "(?i)(?:im |in dem |in der |dem |der )?(?:(?:Satzteil|Angabe) (?:vor|nach) " + + "(?:Nummer|Nr\\.|Buchstabe|Buchst\\.|Satz|Absatz|Abs\\.) \\S+" + + "|(?:Einleitungssatz|Eingangssatz|Einleitung)(?!\\p{L}))"); /** * Wahr, wenn die Phrase ausschließlich aus einem Chapeau-Qualifier besteht (z.B. „im Satzteil vor diff --git a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java index 56b610e..64c6564 100644 --- a/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java +++ b/src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java @@ -591,6 +591,7 @@ public final class BefehlAnwender { bezeichnung, s.stelle().paragraph().map(Stelle.Paragraph::sigel).orElse("§")); case ABSATZ -> new Stelle.AbsatzNr(bezeichnung); case SATZ -> new Stelle.SatzNr(bezeichnung); + case HALBSATZ -> new Stelle.HalbsatzNr(bezeichnung); case NUMMER -> new Stelle.NummerNr(bezeichnung); case BUCHSTABE -> new Stelle.BuchstabeNr(bezeichnung); }; @@ -1276,6 +1277,15 @@ public final class BefehlAnwender { normen.addAll(vonIndex, neue); yield angewandt(befehl, neue.stream().map(Norm::enbez).toList()); } + // Ein Halbsatz ist keine selbständig bezeichnete Einheit: Er lässt sich anfügen + // (siehe wendeAnfuegungAn), aber nicht als Ziel ersetzen oder einfügen — welche Hälfte + // eines Satzes gemeint wäre, sagt keine Bezeichnung. + case HALBSATZ -> + manuell( + befehl, + Grund.NICHT_UNTERSTUETZT, + "Der Halbsatz ist keine selbständig bezeichnete Einheit; nur seine Anfügung ist" + + " umgesetzt."); }; } @@ -1474,6 +1484,15 @@ public final class BefehlAnwender { } return TextErgebnis.ok(neuerText); }); + // Ein Halbsatz ist keine selbständig bezeichnete Einheit: Er lässt sich anfügen + // (siehe wendeAnfuegungAn), aber nicht als Ziel ersetzen oder einfügen — welche Hälfte + // eines Satzes gemeint wäre, sagt keine Bezeichnung. + case HALBSATZ -> + manuell( + befehl, + Grund.NICHT_UNTERSTUETZT, + "Der Halbsatz ist keine selbständig bezeichnete Einheit; nur seine Anfügung ist" + + " umgesetzt."); }; } @@ -1636,6 +1655,21 @@ public final class BefehlAnwender { normen, befehl, text -> TextErgebnis.ok(text.stripTrailing() + " " + befehl.text().strip())); + // Ein Halbsatz beginnt keinen neuen Satz, sondern setzt den bestehenden hinter dem + // Strichpunkt fort. Angehängt wird deshalb wie beim Satz — aber nur, wenn der Zieltext + // tatsächlich auf einen Strichpunkt endet: Sonst stünde der Halbsatz hinter einem Punkt und + // wäre gerade kein Halbsatz. Regelmäßig setzt ihn der Verbund unmittelbar zuvor. + case HALBSATZ -> + bearbeiteText( + normen, + befehl, + text -> + text.stripTrailing().endsWith(";") + ? TextErgebnis.ok(text.stripTrailing() + " " + befehl.text().strip()) + : TextErgebnis.fehler( + "Der Halbsatz setzt einen Strichpunkt voraus; der Zieltext endet nicht" + + " darauf.", + Grund.BESTAND_WIDERSPRICHT)); case NUMMER, BUCHSTABE -> bearbeiteText( normen, diff --git a/src/test/java/eu/mulk/aendggner/EndToEndTest.java b/src/test/java/eu/mulk/aendggner/EndToEndTest.java index 41f30e5..d0273ad 100644 --- a/src/test/java/eu/mulk/aendggner/EndToEndTest.java +++ b/src/test/java/eu/mulk/aendggner/EndToEndTest.java @@ -6,6 +6,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assumptions.assumeTrue; import eu.mulk.aendggner.aenderung.Aenderungsbefehl; +import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Ersetzung; +import eu.mulk.aendggner.aenderung.Aenderungsbefehl.Sammelbefehl; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.StrukturEinfuegung; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.UnbekannterBefehl; import eu.mulk.aendggner.aenderung.Aenderungsbefehl.WortAnker; @@ -1878,20 +1880,31 @@ class EndToEndTest { .filter(b -> b.provenienz().originalText().contains("die Worte")) .toList(); assertThat(wortbefehle).hasSizeGreaterThanOrEqualTo(7); - assertThat(wortbefehle).filteredOn(b -> b instanceof UnbekannterBefehl).hasSize(1); - - // Drei benannte Idiom-Grenzen, alle im Wortlaut festgehalten: - // 5. a) aa) — Satzzeichen-Ersetzung im Verbund mit einer Halbsatz-Anfügung („wird der Punkt - // durch einen Strichpunkt ersetzt und folgender Halbsatz angefügt“). - // 7. a) aa) — „In der Einleitung“ als Ziel, also der Chapeau eines Satzes mit Nummern. - // 12. — die Verweisung auf einen anderen Punkt desselben Artikels („Die Inhaltsübersicht wird - // entsprechend der vorstehenden Nummer 8 Buchst. a geändert“). + assertThat(wortbefehle).noneMatch(b -> b instanceof UnbekannterBefehl); + + // Der Strichpunkt-Verbund („wird der Punkt durch einen Strichpunkt ersetzt und folgender + // Halbsatz angefügt“) und der bezugspunktlose Chapeau („In der Einleitung“) werden gelesen; + // dass beide gleichwohl nicht greifen, liegt an der Quelle und nicht am Werkzeug: Der Stamm + // ist hier die Nachfassung, ihr Wortlaut trägt die Änderung bereits. + assertThat(befehlAn(parseErgebnis, "5. a) aa)")).isInstanceOf(Sammelbefehl.class); + assertThat(befehlAn(parseErgebnis, "7. a) aa)")).isInstanceOf(Ersetzung.class); + + // Eine benannte Grenze bleibt: die Verweisung auf einen anderen Punkt desselben Artikels + // („Die Inhaltsübersicht wird entsprechend der vorstehenden Nummer 8 Buchst. a geändert“). var unerkannt = parseErgebnis.befehle().stream() .filter(b -> b instanceof UnbekannterBefehl) .map(b -> b.provenienz().gliederungsPfad()) .toList(); - assertThat(unerkannt).containsExactly("5. a) aa)", "7. a) aa)", "12."); + assertThat(unerkannt).containsExactly("12."); + } + + private static Aenderungsbefehl befehlAn( + AenderungsgesetzParser.ParseErgebnis ergebnis, String gliederungsPfad) { + return ergebnis.befehle().stream() + .filter(b -> gliederungsPfad.equals(b.provenienz().gliederungsPfad())) + .findFirst() + .orElseThrow(); } /** diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java index 7742a3a..80234b8 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/BefehlErkennerTest.java @@ -1473,4 +1473,45 @@ class BefehlErkennerTest { assertThat(BefehlErkenner.erkenne(text, Stelle.LEER, zitate, PROV)) .containsInstanceOf(Ersetzung.class); } + + /** + * Rheinland-Pfalz: „In Satz 2 wird der Punkt durch einen Strichpunkt ersetzt und folgender + * Halbsatz angefügt: „…““. Zwei Neuerungen in einem Satz — der Strichpunkt als deutsche Nebenform + * des Semikolons und der Halbsatz als Ebene der Anfügung. Die Verbundmechanik selbst bestand + * bereits. + */ + @Test + void erkenntStrichpunktErsetzungMitHalbsatzAnfuegung() { + var befehl = + erkenne( + "In Satz 2 wird der Punkt durch einen Strichpunkt ersetzt und folgender Halbsatz" + + " angefügt: „die Bearbeitungszeit der Abschlussarbeit zählt zu den" + + " Fachstudien.“", + new Stelle(List.of(new Stelle.Paragraph("8"), new Stelle.AbsatzNr("1")))); + + assertThat(befehl).containsInstanceOf(Sammelbefehl.class); + var teile = ((Sammelbefehl) befehl.orElseThrow()).teilbefehle(); + assertThat(teile).hasSize(2); + + assertThat(teile.get(0)).isInstanceOf(Ersetzung.class); + var ersetzung = (Ersetzung) teile.get(0); + assertThat(ersetzung.alt()).isEqualTo("."); + assertThat(ersetzung.neu()).isEqualTo(";"); + assertThat(ersetzung.stelle().anzeigeText()).isEqualTo("§ 8 Absatz 1 Satz 2"); + + assertThat(teile.get(1)).isInstanceOf(Anfuegung.class); + var anfuegung = (Anfuegung) teile.get(1); + assertThat(anfuegung.ebene()).isEqualTo(Ebene.HALBSATZ); + assertThat(anfuegung.text()).contains("die Bearbeitungszeit der Abschlussarbeit"); + } + + /** Der Strichpunkt gilt auch als Subjekt („Der Strichpunkt wird durch ein Komma ersetzt“). */ + @Test + void erkenntDenStrichpunktAlsSubjekt() { + var befehl = erkenne("Der Strichpunkt am Ende wird durch ein Komma ersetzt.", PARAGRAPH_5); + assertThat(befehl).containsInstanceOf(Ersetzung.class); + var ersetzung = (Ersetzung) befehl.orElseThrow(); + assertThat(ersetzung.alt()).isEqualTo(";"); + assertThat(ersetzung.neu()).isEqualTo(","); + } } diff --git a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java index ee7e5c7..13e4442 100644 --- a/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java +++ b/src/test/java/eu/mulk/aendggner/aenderung/parse/StellenParserTest.java @@ -138,4 +138,18 @@ class StellenParserTest { StellenParser.parse("Absatz 1 in der Angabe vor Nummer 1").orElseThrow().anzeigeText()) .isEqualTo("Absatz 1"); } + + /** + * „In der Einleitung“ (Rheinland-Pfalz) ist ein Chapeau-Lokator wie „im Satzteil vor Nummer 1“: + * Er nennt keinen Bezugspunkt und trägt deshalb keine eigene Komponente — die Operation läuft auf + * der Stelle, die der Rahmen bezeichnet. + */ + @Test + void einleitungIstEinChapeauLokator() { + assertThat(StellenParser.istNurChapeau("In der Einleitung")).isTrue(); + assertThat(StellenParser.istNurChapeau("Im Eingangssatz")).isTrue(); + assertThat(StellenParser.istNurChapeau("in dem Einleitungssatz")).isTrue(); + // Ein Wort, das bloß so anfängt, ist keiner. + assertThat(StellenParser.istNurChapeau("In der Einleitungsformel")).isFalse(); + } } diff --git a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java index a1f5cff..39c71cc 100644 --- a/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java +++ b/src/test/java/eu/mulk/aendggner/anwendung/BefehlAnwenderTest.java @@ -1891,4 +1891,72 @@ class BefehlAnwenderTest { assertThat(ergebnis.neu().norm("§ 108").orElseThrow().absaetze().get(0).text()) .doesNotContain("oder Absatz 4"); } + + /** + * Ein Halbsatz setzt den Satz hinter dem Strichpunkt fort; er beginnt keinen neuen. Angefügt wird + * er deshalb wie ein Satz — aber nur hinter einem Strichpunkt. Endet der Zieltext auf einen + * Punkt, so wäre das Angefügte gerade kein Halbsatz, und der Befehl bleibt liegen. + */ + @Test + void halbsatzWirdHinterDemStrichpunktAngefuegt() { + var gesetz = + new Gesetz( + "TestG", + "Testgesetz", + "TestG", + List.of( + new Norm( + "§ 8", + null, + null, + List.of(new Absatz("1", "Erster Satz. Der zweite Satz endet hier;")), + false))); + + var befehl = + new Anfuegung( + stelle(new Stelle.Paragraph("8"), new Stelle.AbsatzNr("1")), + Ebene.HALBSATZ, + null, + "die Bearbeitungszeit zählt zu den Fachstudien.", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz, List.of(befehl)); + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.ANGEWANDT); + assertThat(ergebnis.neu().norm("§ 8").orElseThrow().absaetze().get(0).text()) + .isEqualTo( + "Erster Satz. Der zweite Satz endet hier; die Bearbeitungszeit zählt zu den" + + " Fachstudien."); + } + + @Test + void halbsatzOhneStrichpunktBleibtLiegen() { + var gesetz = + new Gesetz( + "TestG", + "Testgesetz", + "TestG", + List.of( + new Norm( + "§ 8", + null, + null, + List.of(new Absatz("1", "Erster Satz. Der zweite Satz endet hier.")), + false))); + + var befehl = + new Anfuegung( + stelle(new Stelle.Paragraph("8"), new Stelle.AbsatzNr("1")), + Ebene.HALBSATZ, + null, + "die Bearbeitungszeit zählt zu den Fachstudien.", + PROV); + + var ergebnis = BefehlAnwender.anwenden(gesetz, List.of(befehl)); + assertThat(ergebnis.protokoll().get(0).status()).isEqualTo(Status.MANUELL_PRUEFEN); + assertThat(ergebnis.protokoll().get(0).grund()).isEqualTo(Grund.BESTAND_WIDERSPRICHT); + assertThat(ergebnis.protokoll().get(0).begruendung()) + .contains("setzt einen Strichpunkt voraus"); + assertThat(ergebnis.neu().norm("§ 8").orElseThrow().absaetze().get(0).text()) + .isEqualTo("Erster Satz. Der zweite Satz endet hier."); + } } |
