Großschreibung nach Punkt sed Befehl
Großschreibung nach Punkt sed Befehl
Guten Morgen zusammen,
ich suche den sed Befehl, der den ersten Buchstaben eines Wortes, nach einem Punkt, groß schreibt.
Falsch:
Das Wetter ist schön. trotzdem möchte ich nicht in die Sonne!
Richtig
Das Wetter ist schön. Trotzdem möchte ich nicht in die Sonne!
Hintergrund: Ich habe eine automatisierte Stapelverarbeitung von TXT Dateien via Aspell erstellt. Leider erkennt Aspell die Satzzeichen in meinem Dokument nicht korrekt. Deshalb würde ich gerne mittels sed Befehl das Problem lösen.
ich suche den sed Befehl, der den ersten Buchstaben eines Wortes, nach einem Punkt, groß schreibt.
Falsch:
Das Wetter ist schön. trotzdem möchte ich nicht in die Sonne!
Richtig
Das Wetter ist schön. Trotzdem möchte ich nicht in die Sonne!
Hintergrund: Ich habe eine automatisierte Stapelverarbeitung von TXT Dateien via Aspell erstellt. Leider erkennt Aspell die Satzzeichen in meinem Dokument nicht korrekt. Deshalb würde ich gerne mittels sed Befehl das Problem lösen.
Re: Großschreibung nach Punkt sed Befehl
\u bedeutet Uppercase und bezieht sich auf das folgende Zeichen:
EDIT:
globales g ergänzt
Code: Alles auswählen
sed -E 's/(\. *)([a-zäöü])/\1\u\2/g'
globales g ergänzt
Re: Großschreibung nach Punkt sed Befehl
Warum so Umständlich?
Oder hab ich was übersehen? Das "*" hab ich absichtlich weggelassen, eine fehlende Leerstelle nach dem Satzpunkt sollte bereits durch den Spellchecker erkannt worden sein.
Was wir beide nicht beachten: wenn ein Satz am Zeilenende endet und der nächste Satz erst auf der folgenden Zeile oder im nächsten Absatz beginnt.
Code: Alles auswählen
sed 's_\(\. .\)_\U\1_g'
Was wir beide nicht beachten: wenn ein Satz am Zeilenende endet und der nächste Satz erst auf der folgenden Zeile oder im nächsten Absatz beginnt.
Re: Großschreibung nach Punkt sed Befehl
Perfekt das funktioniert. Vielen lieben Dank euch beiden
eggy hat geschrieben:13.06.2022 11:08:26Warum so Umständlich?Oder hab ich was übersehen? Das "*" hab ich absichtlich weggelassen, eine fehlende Leerstelle nach dem Satzpunkt sollte bereits durch den Spellchecker erkannt worden sein.Code: Alles auswählen
sed 's_\(\. .\)_\U\1_g'
Was wir beide nicht beachten: wenn ein Satz am Zeilenende endet und der nächste Satz erst auf der folgenden Zeile oder im nächsten Absatz beginnt.
Re: Großschreibung nach Punkt sed Befehl
Sowas?eggy hat geschrieben:13.06.2022 11:08:26Was wir beide nicht beachten: wenn ein Satz am Zeilenende endet und der nächste Satz erst auf der folgenden Zeile [...] beginnt.
Code: Alles auswählen
sed -E 's/(\. .)/\U\1/g;:M /\. *$/{N;s/(\. *\n? *.)/\U\1/g;bM}'
Den eigentlichen Befehl ergänzt...
Re: Großschreibung nach Punkt sed Befehl
Würde das ganze auch mit einem Ausrufezeichen funktionieren (statt dem Punkt)?
Re: Großschreibung nach Punkt sed Befehl
Statt des Punktes (\. --> !):
Punkt oder Ausrufezeichen (\. --> (\.|!)):
Code: Alles auswählen
sed -E 's/(! .)/\U\1/g;:M /! *$/{N;s/(! *\n? *.)/\U\1/g;bM}'
Code: Alles auswählen
sed -E 's/((\.|!) .)/\U\1/g;:M /(\.|!) *$/{N;s/((\.|!) *\n? *.)/\U\1/g;bM}'
Re: Großschreibung nach Punkt sed Befehl
Zur Erklärung:
Das s steht für substitute, also ersetzen
Siehe auch https://www.gnu.org/software/sed/manual ... mmand.html
Der "_" ist das Trennzeichen für sed, man kann auch anderes nehmen, "\", "_", "-" sind die gebräuchlisten, ich mag "_" weil die Teile so auch visuell etwas getrennt werden.
Die runden Klammer sind zur Bestimmung der Gruppen, damit sed die Klammer als sed-Sonderzeichen wahrnimmt muss maskiert werden, daher "\(" und "\)".
Auf die Gruppen kann man dann später mit "\1" zurückgreifen, hätte man mehrere Gruppen "\2", "\3" usw.
Das \U sagt mach mal aus dem Folgenden Uppercase. Im Link sind die Unterschiede zwischen klein u und groß etc erklärt, einfach mal da selbst nachlesen.
g steht für global, also nicht nur die erst Fundstelle ersetzen.
Was fehlt noch? "\. ."
Bei den sed Regex gibt es als Sonderzeichen den Punkt, der "beliebiges Zeichen" bedeutet. Das ist der Punkt ohne alles, der hintere der beiden, also nur ".".
Da man aber auch "normale" Punkte ohne Sonderbedeutung, also ganz normale Satzzeichenpunkte benutzen können will, muss man die irgendwie unterscheiden, via Maskierung. Das passiert im Beispiel hier vorne, der "\." ist der maskierte Punkt, der normale Satzzeichenpunkt. Und dazwischen ist das Leerzeichen, dass man Zwischen nem Satzende und nem Neuen Satzanfang erwartet.
Noch Fragen dazu?
<werbung>
Falls es jemand genauer wissen will: Meillos kleinen Regexkurs gibts ein paar Threads weiter.
Diese Woche gibt's des Dinos Python Regechsen im Sonderangebot.
</werbung>
@tobo: magst Du Deins auch noch erklären?
Code: Alles auswählen
sed 's_\(\. .\)_\U\1_g'
Siehe auch https://www.gnu.org/software/sed/manual ... mmand.html
Der "_" ist das Trennzeichen für sed, man kann auch anderes nehmen, "\", "_", "-" sind die gebräuchlisten, ich mag "_" weil die Teile so auch visuell etwas getrennt werden.
Die runden Klammer sind zur Bestimmung der Gruppen, damit sed die Klammer als sed-Sonderzeichen wahrnimmt muss maskiert werden, daher "\(" und "\)".
Auf die Gruppen kann man dann später mit "\1" zurückgreifen, hätte man mehrere Gruppen "\2", "\3" usw.
Das \U sagt mach mal aus dem Folgenden Uppercase. Im Link sind die Unterschiede zwischen klein u und groß etc erklärt, einfach mal da selbst nachlesen.
g steht für global, also nicht nur die erst Fundstelle ersetzen.
Was fehlt noch? "\. ."
Bei den sed Regex gibt es als Sonderzeichen den Punkt, der "beliebiges Zeichen" bedeutet. Das ist der Punkt ohne alles, der hintere der beiden, also nur ".".
Da man aber auch "normale" Punkte ohne Sonderbedeutung, also ganz normale Satzzeichenpunkte benutzen können will, muss man die irgendwie unterscheiden, via Maskierung. Das passiert im Beispiel hier vorne, der "\." ist der maskierte Punkt, der normale Satzzeichenpunkt. Und dazwischen ist das Leerzeichen, dass man Zwischen nem Satzende und nem Neuen Satzanfang erwartet.
Noch Fragen dazu?
<werbung>
Falls es jemand genauer wissen will: Meillos kleinen Regexkurs gibts ein paar Threads weiter.
Diese Woche gibt's des Dinos Python Regechsen im Sonderangebot.
</werbung>
@tobo: magst Du Deins auch noch erklären?
Re: Großschreibung nach Punkt sed Befehl
Ihr habt mir richtig weitergeholfen. Durch deine Erklärung @eggy konnte ich jetzt auch weitere Befehle schreiben
Re: Großschreibung nach Punkt sed Befehl
Die Erklärung von
schließt eggys Erklärung mit ein. Das
ist nichts anderes als eggys Lösung umgeschrieben und leicht ergänzt. Der Optionsschalter -E erlaubt es Erweiterte Reguläre Ausdrücke (ERE) zu verwenden, so dass die Zeichen (){}+?| nicht durch das Voranstellen eines \ escaped werden müssen.
Einziger Unterschied zu eggys Code ist die Ausweitung auf ". oder !" mittels des Oder-Vergleichs mit |. Dieses Oder ist nach beiden Seiten gierig und würde alle möglichen Zeichen in den Vergleich einbeziehen, weshalb der Oder-Vergleich separat geklammert werden muss. Ohne Klammer würde der Vergleich lauten: "." oder "! .", wäre also nur für das ! korrekt. Die zusätzliche Klammer hat für die Rückwärtsreferenz \1 keine Bedeutung - man fängt einfach von links an die öffnenden Klammern zu zählen, um die entsprechende Rückwärtsreferenz zu finden. Die Oder-Klammer wäre also \2.
Der Kommandotrenner ; erlaubt es mehrere sed-Kommandos hintereinander auszuführen. Alternativ müsste man sie jeweils einzeln mit Optionsschalter -e angeben.
Die allgemeine Vorgehensweise von sed ist: Eine Zeile wird eingelesen, das Skript (die jeweilige Kommandosequenz) darauf angewendet und die bearbeitete Zeile wird dann ausgegeben. Jetzt vorgestellt, eine Zeile wurde eingelesen, in allen "Punkt/Ausrufezeichen + Leerzeichen + Kleinbuchstaben"-Kombinationen wurden die Kleinbuchstaben durch den entsprechenden Großbuchstaben ersetzt, dann kommt der ; zur Kommandotrennung und dann der folgende Teil:
Das ist eine Schleife, die den Fall abdecken soll, dass die Zeile mit einem Punkt endet und das erste Wort, in der Zeile darauf, mit einem Kleinbuchstaben beginnt. Die Schleife wird dabei auf die bereits bearbeitete Zeile angewendet, also nicht auf die Ausgangszeile. Allgemein, ohne auf die Feinheiten einzugehen, steht da jetzt sowas drin:
:M gibt also eine Marke (ein Sprungziel) mit Namen M an, b springt (ohne das eine Bedingung erfüllt sein muss) zu der dahinter angegebenen Marke. Mit t und T würde es auch bedingte Sprünge in sed geben, je nachdem, ob eine Substitution erfolgt ist oder nicht.
Ist das Suchmuster im Inneren der Schleife erfüllt, dann wird eine Befehlskette abgearbeitet, an deren Ende wieder der Sprung zur Marke steht. Die Befehlskette ist in {} eingeschlossen, damit sich alle Befehle der Befehlskette auf das positiv erfüllte Suchmuster beziehen. Fehlen die {}, dann wird nur der erste Befehl der Befehlskette ausgeführt, wenn das Suchmuster vorhanden ist. Alle anderen Befehle würden immer ausgeführt werden.
Erfüllt sich das Suchmuster nicht, dann wird die Befehlskette nicht abgearbeitet (das ist das Abbruchkriterium, die Sprungaufforderung wird nicht erreicht - deswegen keine Endlosschleife), die Zeile(n) wird/werden ausgegeben und es wird die nächste Zeile zur Bearbeitung eingelesen.
Im Detail:
Das Suchmuster
ist erfüllt, wenn ein . oder ! gefunden wird, dem beliebig viele (*) Leerzeichen (heißt möglicherweise auch kein Leerzeichen) und das Zeilenende ($) folgen. Das Zeilenende ist kein darstellbares Zeichen, sondern eine interne Konvention.
Die Befehlskette
beginnt damit, dass die nächste Zeile eingelesen wird (N) und mit einem zusätzlichen Zeilenumbruch hinter die bereits vorhandene(n) Zeile(n) gehängt wird. Möglicher Plural, weil das ja eine Schleife ist - das ist also ein Part, der sich unter Umständen wiederholt. Um das nochmal zu verdeutlichen, was bislang geschehen ist: Es wird eine Zeile eingelesen und darin die entsprechenden Kleinbuchstaben umgewandelt, dann wird geschaut, ob diese Zeile mit einem . oder ! endet. Falls ja, dann wird ein Zeilenumbruch und die nächste Zeile hinzugefügt und der Rest der Befehlskette darauf angewendet. Falls nein, dann wird die Zeile ausgegeben.
Das mit dem Zeilenumbruch hört sich jetzt erstmal unlogisch an, schließlich haben die Zeilen ja einen Zeilenumbruch. Sed entfernt allerdings diesen Zeilenumbruch, so dass die Befehle auf dem reinen Text angewendet werden und fügt sie dann der Ausgabe wieder hinzu.
Die folgende Substitution ist soweit bekannt, mit dem Unterschied, dass jetzt im Suchteil der Substitution nach ". oder !, gefolgt von beliebig vielen Leerzeichen, gefolgt von einem oder keinem Zeilenumbruch (\n?; ? bedeutet 0 oder ein Mal), gefolgt von beliebig vielen Leerzeichen, gefolgt von einem Zeichen", gesucht wird. 0 oder 1 Zeilenumbruch, weil es bei der neu hinzugekommenen Zeile ja verschiedene Fälle gibt, die beachtet werden müssen. Sie kann mit einem kleingeschriebenen Wort beginnen (\. *\n *.) und/oder mittendrin (ohne Zeilenumbruch) kann ein kleingeschriebenes Wort auf (\.|!) folgen (\. *.).
Code: Alles auswählen
sed -E 's/((\.|!) .)/\U\1/g;:M /(\.|!) *$/{N;s/((\.|!) *\n? *.)/\U\1/g;bM}'
Code: Alles auswählen
sed -E 's/((\.|!) .)/\U\1/g;
Einziger Unterschied zu eggys Code ist die Ausweitung auf ". oder !" mittels des Oder-Vergleichs mit |. Dieses Oder ist nach beiden Seiten gierig und würde alle möglichen Zeichen in den Vergleich einbeziehen, weshalb der Oder-Vergleich separat geklammert werden muss. Ohne Klammer würde der Vergleich lauten: "." oder "! .", wäre also nur für das ! korrekt. Die zusätzliche Klammer hat für die Rückwärtsreferenz \1 keine Bedeutung - man fängt einfach von links an die öffnenden Klammern zu zählen, um die entsprechende Rückwärtsreferenz zu finden. Die Oder-Klammer wäre also \2.
Der Kommandotrenner ; erlaubt es mehrere sed-Kommandos hintereinander auszuführen. Alternativ müsste man sie jeweils einzeln mit Optionsschalter -e angeben.
Die allgemeine Vorgehensweise von sed ist: Eine Zeile wird eingelesen, das Skript (die jeweilige Kommandosequenz) darauf angewendet und die bearbeitete Zeile wird dann ausgegeben. Jetzt vorgestellt, eine Zeile wurde eingelesen, in allen "Punkt/Ausrufezeichen + Leerzeichen + Kleinbuchstaben"-Kombinationen wurden die Kleinbuchstaben durch den entsprechenden Großbuchstaben ersetzt, dann kommt der ; zur Kommandotrennung und dann der folgende Teil:
Code: Alles auswählen
sed -E ':M /(\.|!) *$/{N;s/((\.|!) *\n? *.)/\U\1/g; bM}'
Code: Alles auswählen
sed -E ':Marke /Suchmuster/{Befehle; gehe_zu_Marke}'
Ist das Suchmuster im Inneren der Schleife erfüllt, dann wird eine Befehlskette abgearbeitet, an deren Ende wieder der Sprung zur Marke steht. Die Befehlskette ist in {} eingeschlossen, damit sich alle Befehle der Befehlskette auf das positiv erfüllte Suchmuster beziehen. Fehlen die {}, dann wird nur der erste Befehl der Befehlskette ausgeführt, wenn das Suchmuster vorhanden ist. Alle anderen Befehle würden immer ausgeführt werden.
Erfüllt sich das Suchmuster nicht, dann wird die Befehlskette nicht abgearbeitet (das ist das Abbruchkriterium, die Sprungaufforderung wird nicht erreicht - deswegen keine Endlosschleife), die Zeile(n) wird/werden ausgegeben und es wird die nächste Zeile zur Bearbeitung eingelesen.
Im Detail:
Das Suchmuster
Code: Alles auswählen
/(\.|!) *$/
Die Befehlskette
Code: Alles auswählen
{N; s/((\.|!) *\n? *.)/\U\1/g; bM}
Das mit dem Zeilenumbruch hört sich jetzt erstmal unlogisch an, schließlich haben die Zeilen ja einen Zeilenumbruch. Sed entfernt allerdings diesen Zeilenumbruch, so dass die Befehle auf dem reinen Text angewendet werden und fügt sie dann der Ausgabe wieder hinzu.
Die folgende Substitution ist soweit bekannt, mit dem Unterschied, dass jetzt im Suchteil der Substitution nach ". oder !, gefolgt von beliebig vielen Leerzeichen, gefolgt von einem oder keinem Zeilenumbruch (\n?; ? bedeutet 0 oder ein Mal), gefolgt von beliebig vielen Leerzeichen, gefolgt von einem Zeichen", gesucht wird. 0 oder 1 Zeilenumbruch, weil es bei der neu hinzugekommenen Zeile ja verschiedene Fälle gibt, die beachtet werden müssen. Sie kann mit einem kleingeschriebenen Wort beginnen (\. *\n *.) und/oder mittendrin (ohne Zeilenumbruch) kann ein kleingeschriebenes Wort auf (\.|!) folgen (\. *.).