Wie erstelle ich einen (sed) regulären Ausdruck, der alle Vorkommen eines Zeichens ersetzt und das letzte löscht?

Wie erstelle ich einen (sed) regulären Ausdruck, der alle Vorkommen eines Zeichens ersetzt und das letzte löscht?

Ich habe mit Folgendem zu kämpfen. Ich verwende Befehle wie diese in meinem Mac-Terminal, um meinen regulären Ausdruck zu testen:

echo 'inputstring' | sed (-E) '/s///g'

Ich versuche, einen regulären Ausdruck zu erstellen, der:

  • genau dann, wenn ein Wort mit dem Buchstaben „o“ endet, dann:
  • löscht dieses wortfinale 'o'
  • ersetzt alle Vorkommen des Buchstabens 'i' durch 'a' in diesem Wort

In diesem Fall ist die Eingabezeichenfolge filo fililo felo faleund die erwartete Ausgabe istfal falal fel fale

Ich kann einen regulären Ausdruck erstellen, der entweder die Löschung oder die Ersetzung vornimmt, weiß aber nicht, wie ich sie kombinieren kann. Wenn ich eine Halbspalte dazwischen setze, weiß ich nicht, wie ich den bedingten Teil einfügen kann.

Ich habe auch Probleme, die Position „Wortende“ zu definieren. Ich habe sie verwendet, \baber sie scheint nicht zu funktionieren (anders als $beim Ende einer Zeichenfolge).

Antwort1

Ich würde es hierfür nicht verwenden sed, aber wenn es eine Lernübung ist sed, führen Sie eine Schleife wie diese aus:

sed -E 's/$/ /
  :a
  s/i([[:alnum:]]*o[^[:alnum:]])/a\1/
  ta
  s/([[:alnum:]]*)o([^[:alnum:]])/\1\2/
  ta
  s/ $//'
  • In der ersten Zeile füge ich am Ende ein Leerzeichen hinzu, damit wir das Zeilenende wie jedes andere Wortende behandeln können. Die letzte Zeile entfernt dieses Leerzeichen später.
  • Der sBefehl in Zeile 3 sucht nach Vorkommen von iin einem Wort, das mit endet, ound ersetzt es durch a. Der tBefehl springt zurück zur Markierung, :aum dies für alle Wörter zu wiederholen, die imit o- enden.
  • Nun entfernt die fünfte Zeile die Endung ound eine weitere Schleife. Beachten Sie, dass aus einem Wort, das mit endet oo, beide entfernt werden; es ist unklar, ob dies erwünscht ist.

Nur zu Referenzzwecken verwende ich eine sedVersion, die die oOption für den sBefehl unterstützt, die nur bedeutet, den übereinstimmenden Teil beizubehalten und den Rest wegzuwerfen. Außerdem kennt sie das \hin der Ersetzung, das durch den Inhalt des Haltebereichs ersetzt werden soll. Dadurch wird die Aufgabe zu einem Einzeiler:

sed -E ':a;h;s/([[:alnum:]]*)o($|[^[:alnum:]])/\1\2/o;T;y/i/a/;x;s//\h/;ba'

Antwort2

Ohhhhwäre in einem solchen Fall genauer und flexibler:

awk '{ for(i=1;i<=NF;i++) 
       if ($i~/o$/) { sub(/o$/,"",$i); gsub("i","a",$i) } }1' <<<"filo fililo felo fale"

Die Ausgabe:

fal falal fel fale

AlternativePythonBefehlszeilenansatz:

python -c 'import sys,re; s = sys.stdin.read().strip(); 
print(re.sub(r"\b(\S+)o\b", lambda m: m.group(1).replace("i","a"), s))' <<<"filo fililo felo fale"
fal falal fel fale

Antwort3

Ich bin nicht sicher, ob das mit möglich ist sed(ich vermute, dass es das wahrscheinlich nicht ist), aber mit Python ist es wirklich einfach! Hier ist ein Skript, das genau das macht, was Sie wollen:

#!/usr/bin/env python2
# -*- coding: ascii -*-
"""modify_strings.py"""

import sys
import re
import fileinput

# Iterate over lines of input
# (either read from files or from stdin)
for line in fileinput.input():

    # Split each line into tokens and preserve whitespace
    tokens = re.split(r'(\s+)', line)

    # Iterate over tokens
    for token in tokens:

        # If a word ends in 'o' then
        # perform the desired transformation
        if token.endswith('o'):
            token = token[:-1].replace('i', 'a')

        # Print out each token
        sys.stdout.write(token)

Sie können es wie folgt ausführen:

echo 'filo fililo felo fale' | python modify_strings.py

Und es erzeugt (wie gewünscht) die folgende Ausgabe:

fal falal fel fale

Wenn Sie wirklich sedmitmachen möchten, können Sie Ihr Ziel wahrscheinlich erreichen, indem Sie es mit ein wenig Shell-Skripting erweitern. Das könnte etwa wie das folgende bashSkript aussehen:

#!/usr/bin/env bash

# modify-strings.bash

for word in "$@"; do
    if grep -q 'o$' <<<"${word}"; then
        echo -n "${word} " | sed -e 's/i/a/g' -e 's/o$//';
    else
        echo -n "${word} ";
    fi;
done
echo

Sie würden dieses Skript folgendermaßen aufrufen:

bash modify-strings.bash filo fililo felo fale

verwandte Informationen