
Ich habe keine Erfahrung mit Regex und sed und versuche, einen meiner Meinung nach unkomplizierten Regex zu erstellen: Ich möchte den Buchstaben am Ende des Wortes entfernen, wenn es ein „o“ ist.
- Eingabezeichenfolge: Hallo, Hallo
- Erwartete Ausgabe: Hell Hell
Die gute Nachricht: Ich kann das „o“ entfernen, wenn es am Ende der Zeichenfolge steht:
$ echo 'Hello Hello' |sed 's/\(.*\)o/\1/g'
Hello Hell
$ echo 'Hello Hello' |sed 's/\(.*\)o$/\1/g'
Hello Hell
Die schlechte Nachricht: Ich kann es nicht aus Wörtern entfernen, die weiter vorne in der Zeichenfolge stehen. Ich habe das mit allen Ankersymbolen versucht, die mir einfallen. Das Ergebnis ist, dass keines der wortfinalen 'o's entfernt wird:
$ echo 'Hello Hello' |sed 's/\(.*\)o\b/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\>/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\W/\1/g'
Hello Hello
$ echo 'Hello Hello' |sed 's/\(.*\)o\s/\1/g'
Hello Hello
Können Sie mir bitte helfen, meinen Verstand wiederzuerlangen, indem Sie mir sagen, was ich falsch mache?
Update: Ich habe den deutlichen Eindruck, dass mein Rechner andere Ergebnisse liefert als andere Leute. Ich verwende das Terminalfenster auf meinem Macbook. Wenn jemand etwas Licht ins Dunkel bringen kann, sagen Sie es mir bitte.
Antwort1
echo 'Hello Hello' | sed 's/o$//'
scheint mir nützlicher als Ihre
echo 'Hello Hello' | sed 's/\(.*\)o$/\1/g'
In Ihrer Frage steht, dass die Ausgabe von
echo 'Hello Hello' | sed 's/\(.*\)o\b/\1/g'
war Hello Hello
, aber für mich ist es so Hello Hell
. Sie können das korrigieren zu
echo 'Hello Hello' | sed 's/\([^o]*\)o\b/\1/g'
Aber
echo 'Hello Hello' | sed 's/o\b//g'
scheint mir besser.
Antwort2
Das Entfernen von „ o
am Ende von Wörtern“ entspricht dem Entfernen von „ao“ zwischen einem Wortzeichen und einem Nicht-Wortzeichen (oder dem EOL). Also:
sed -r 's/(\w)o(\W|$)/\1\2/g'
Antwort3
Ich frage mich, ob „irgendwie“ space
nicht Ihr Worttrennzeichen ist. Versuchen Sie es mit etwas wie dem Folgenden:
$ echo hello hello | sed -e 's/o / /g;s/o$//'
hell hell
.
Das Problem bei diesem Beispiel ist, dass Sie dasselbe auch für und ,
und alle anderen Worttrennzeichen tun müssen . Match o
gefolgt von einem anderen bestimmten Zeichen mit []
like o[ \.,]
. Aus irgendeinem Grund funktioniert das nicht für EOL $
, also fügen Sie eine weitere Suchzeichenfolge mit hinzu ;
. Beispiel:
$ echo hello hello, hello. toot hello | sed -e 's/o\([ \.,]\)/\1/g;s/o$//'
hell hell, hell. toot hell
$ echo $SHELL
/bin/bash
$ sed --version
sed (GNU sed) 4.4
$ set | grep IFS
IFS=$' \t\n'
Antwort4
Ich habe dies mit allen Ankersymbolen versucht, die mir eingefallen sind.
Es liegt nicht an den Ankern, sondern an der Tatsache, dass Sie eine gierige Übereinstimmung mit dem Asterisk haben. Der \(.*\)o
Ausdruck stimmt übereineine möglichst lange Zeichenfolge, also wird es alles auffressen bis zumzuletzt o
. Es könnte o
auch mit früheren übereinstimmen.
Es ist jedoch sinnlos, etwas zu erfassen und dann zurückzugeben. Sie könnten das \(.*\)
und das einfach \1
vollständig entfernen.
Diese würden also (zumindest in GNU sed) die o
's am Ende von Wörtern entfernen:
sed 's/o\>//g'
sed 's/o\b//g'
Dies natürlich nur am Ende des Strings:
sed 's/o$//g'
Und dies entfernt ein o
, zusammen mit einem folgenden Nicht-Wort-Zeichen (z. B. das Leerzeichen nach Hello
):
sed 's/o\W//g'
Wenn Ihr / oder sed
nicht unterstützt , müssen Sie etwas anderes tun. Dies würde eine Übereinstimmung gefolgt von einem nicht-alphanumerischen Zeichen oder dem Zeilenende ergeben:\<
\>
\b
o
$ echo "jello, jello" | sed -E -e 's/o([^[:alnum:]]|$)/\1/g'
jell, jell
Dies funktioniert beispielsweise in der sed
mit OS X/macOS mitgelieferten Version.
Perl-Regexe unterstützen das Hinzufügen eines Fragezeichens an *
oder +
, um sie nicht-gierig zu machen. Dann würden sie mit demkürzesteMögliche Zeichenfolge:
echo "jello, jello" | perl -pe 's/(.*?)o/$1/g'
jell, jell