2016-07-03 6 views
1

In einem POSIX-Shell-Skript muss ich alle Vorkommen von Text innerhalb von {{ und }} finden und den Text zusammen mit den umgebenden Klammern durch ein Sternchen ersetzen.Wie wird zwischen einem Start-Delimiter und einem End-Delimiter verglichen, so dass der Text nicht den End-Delimiter enthält (d. H. Nicht-gierige Übereinstimmung)?

Zum Beispiel, wenn der Eingang

{{ abc }} def {{ ghi {jkl} mno }} pqr 

dann muss der Ausgang seine

* def * pqr 

Ich habe dies mit einem sed Befehl kommt nicht in der Lage gewesen, das funktioniert.

Ich habe ein paar Befehle ausprobiert, aber sie funktionieren nicht. Der folgende Befehl erzeugt z. B. nicht die gewünschte Ausgabe, da sed gierige Übereinstimmung ergibt. Es entspricht {{ abc }} def {{ ghi {jkl} mno }} als erste Übereinstimmung statt nur {{ abc }}.

$ echo "{{ abc }} def {{ ghi {jkl} mno }} pqr" | sed 's/{{.*}}/*/g' 
* pqr 

Hier ist ein weiteres Beispiel, das, weil es zu wenig passende endet nicht funktioniert. Es passt nicht {{ ghi {jkl} mno }} (die wir übereinstimmen möchten), da dieser Teil der Zeichenfolge darin } enthält.

$ echo "{{ abc }} def {{ ghi {jkl} mno }} pqr" | sed 's/{{[^}]*}}/*/g' 
* def {{ ghi {jkl} mno }} pqr 

Wie kann ich sonst so ein Match machen?

Ich habe durch Non greedy regex matching in sed? gegangen, aber die Lösungen dort nicht helfen, weil ich hier alles zwischen {{ und }} mit Ausnahme einer bestimmten Folge von zwei aufeinanderfolgenden Zeichen übereinstimmen soll, das heißt }}. Wenn ich versuchen würde, zwischen den Trennzeichen alles außer einem einzelnen Zeichen abzugleichen, hätten die Antworten auf diese Frage geholfen.

Antwort

0

Wenn Sie einen regulären Ausdruck haben, der mit etwas übereinstimmt, das "}}" nicht enthält, dann können Sie es als "{{" exp "}}" verwenden. Leider hat sed keinen zusätzlichen Regexp-Operator. Viele Regexp-Implementierungen tun dies, da das Komplement einer regulären Sprache regelmäßig ist. Wir wissen also, dass es existiert, aber wir müssen es nur manuell erstellen.

In einem besser lesbaren Format als sed ist etwas in der Nähe "{{" ([^}]* ("}" [^}])?)* "}}".

In richtigen sed das ist:

$ echo "{{ abc }} def {{ ghi {jkl} mno }} pqr" \ 
    | sed 's/{{\([^}]*\(}[^}]\)\?\)*}}/*/g' 
* def * pqr 
$ 

Das ist nicht genau sein kann, was Sie wollen, je nachdem, ob oder nicht Sie drei Klammern in einer Reihe erwarten. Was soll mit diesem abc {{ def { ghi }}} passieren? Wenn Sie Klammern wirklich ausbalancieren müssen, werden Sie damit aus dem Bereich der normalen Sprachen und in kontextfreie Sprachen ausscheiden, die leistungsfähigere Werkzeuge benötigen.

Mit Ihrem Benutzernamen möchten Sie vielleicht ein Buch über formale Sprachen und Automatentheorie lesen. Es mag "alte" Technologie sein, aber es ist sehr leistungsfähig und wird den ganzen Tag von allen Arten von Technologie genutzt.