aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/Aenderungsbefehl.java2
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/parse/BefehlErkenner.java33
-rw-r--r--src/main/java/eu/mulk/aendggner/aenderung/parse/StellenParser.java12
-rw-r--r--src/main/java/eu/mulk/aendggner/anwendung/BefehlAnwender.java34
4 files changed, 67 insertions, 14 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,