Wie verwende ich [\ w] + in regulären Ausdrücken in sed?

24

Ich bin auf Windows, aber ich denke, meine Frage ist hier noch richtig gestellt.

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

Mir ist aufgefallen, dass folgendes funktioniert (ausgeben here):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

Dies funktioniert jedoch nicht (es wird nichts ausgegeben):

echo here | grep -E "[\w]+"

Das macht wieder (ausgeben here):

echo here | grep -P "[\w]+"

[\w]Ich nehme also an, dass es sich um etwas Spezielles für reguläre Perl-Ausdrücke handelt. Ist das korrekt?

Also lass uns reden sed. Das funktioniert (Ausgabe gone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

Und das tut es auch nicht (Ausgabe here):

echo here | sed -r "s/[\w]+/gone/"

Wie kann ich nun reguläre Perl-Ausdrücke für sed aktivieren?

bers
quelle

Antworten:

11

Verschiedene Tools und Versionen davon unterstützen verschiedene Varianten von regulären Ausdrücken. In der Dokumentation der einzelnen Artikel erfahren Sie, was sie unterstützen.

Es gibt Standards, mit denen man sich auf ein Minimum an Funktionen verlassen kann, die für alle konformen Anwendungen verfügbar sind.

Zum Beispiel alle modernen Implementierungen sedund grepImplementierungen grundlegender regulärer Ausdrücke gemäß POSIX (mindestens die eine oder andere Version des Standards, aber dieser Standard hat sich diesbezüglich in den letzten Jahrzehnten nicht wesentlich weiterentwickelt).

In POSIX BRE und ERE haben Sie die [:alnum:]Zeichenklasse. Das stimmt mit Buchstaben und Ziffern in Ihrem Gebietsschema überein (beachten Sie, dass dies oft viel mehr umfasst, als a-zA-Z0-9wenn das Gebietsschema C ist).

So:

grep -x '[[:alnum:]_]\{1,\}'

stimmt mit einem oder mehreren Alumni oder _ überein.

[\w]wird von POSIX benötigt, um entweder mit einem Backslash oder mit einem Backslash übereinzustimmen w. Sie werden also keine grepoder eine sedImplementierung finden, wo diese verfügbar ist (es sei denn, dies erfolgt über nicht standardmäßige Optionen).

Das Verhalten für \wAlleine wird von POSIX nicht spezifiziert, daher dürfen Implementierungen tun, was sie wollen. GNU grephat das vor langer Zeit hinzugefügt.

grepFrüher hatte GNU eine eigene Regexp-Engine, jetzt verwendet es jedoch die der GNU-Libc (obwohl es eine eigene Kopie einbettet).

Es soll zu Alumni und Unterstrich in Ihrem Gebietsschema passen. Es hat jedoch derzeit den Fehler, dass es nur Einzelbyte-Zeichen entspricht (z. B. nicht in einem UTF-8-Gebietsschema, obwohl dies eindeutig ein Buchstabe ist und obwohl es in allen Gebietsschemas übereinstimmt, in denen es sich um ein einzelnes Zeichen handelt Charakter).

Es gibt auch einen \wRegexp-Operator in Perl-Regexp und in PCRE. PCRE / Perl sind keine regulären POSIX-Ausdrücke, sondern nur eine andere Sache.

Mit der Art und Weise, wie GNU grep -PPCRE verwendet, hat es das gleiche Problem wie ohne -P. Es kann jedoch mithilfe von umgangen werden (*UCP)(obwohl dies auch Nebenwirkungen in Nicht-UTF8-Gebietsschemas hat).

GNU sedverwendet auch die regulären Ausdrücke der GNU libc für ihre eigenen regulären Ausdrücke. Es benutzt es so, dass es nicht den gleichen Fehler wie GNU hat grep.

GNU sedunterstützt keine PCREs. Der Code enthält einige Beweise dafür, dass es schon einmal versucht wurde, aber er scheint nicht mehr auf der Tagesordnung zu stehen.

Wenn Sie reguläre Ausdrücke von Perl möchten, verwenden Sie einfach perl.

Ansonsten würde ich sagen, dass es besser ist, den Standard und die Verwendung beizubehalten, als sich auf eine falsche Nicht-Standard-Funktion Ihrer speziellen Implementierung von sed/ zu verlassen .grep[_[:alnum:]]

Stéphane Chazelas
quelle
[_[:alnum:]]ist eine nette Abhilfemaßnahme, mit der ich es genau so erweitern kann [\w/]( [_[:alnum:]/]in diesem Fall).
Bers
1
Diese Antwort ist jetzt im Hinblick auf die Einschränkungen von GNU veraltet grep.
Stéphane Chazelas
7

Sie haben Recht - \wist Teil von PCRE - Perl - kompatiblen regulären Ausdrücken. Es ist jedoch nicht Teil des 'Standard'-Regex. http://www.regular-expressions.info/posix.html

Einige Versionen von sedunterstützen es möglicherweise, aber ich würde vorschlagen, dass die einfachste Möglichkeit die Verwendung perlim sedModus ist, indem Sie das -pFlag angeben . (Zusammen mit dem -e). (Weitere Einzelheiten in perlrun)

Aber []in diesem Beispiel brauchen Sie das nicht zu umgehen - das ist für Gruppen von gültigen Sachen.

echo here  | perl -pe 's/\w+/gone/'

Oder unter Windows:

C:\>echo here  | perl -pe "s/\w+/gone/"
gone
C:\>echo here  | perl -pe "s/[\w\/]+/gone/"
gone

Siehe perlrefür mehr PCRE Zeug.

Sie können Perl hier herunterladen: http://www.activestate.com/activeperl/downloads

Sobrique
quelle
Bitte beachten Sie den Unterschied zwischen \wund [\w]in meiner Frage. Ich werde es mit den Ausgaben der einzelnen Befehle aktualisieren, um zu verdeutlichen, welche funktionieren und welche nicht. Insbesondere sedversteht \w, aber nicht [\w]. Außerdem muss ich [\w]arbeiten, weil ich [\w/]zum Beispiel verwenden möchte .
Bers
In diesem Fall handelt es sich wahrscheinlich um ein Zitatproblem. So oder so - perlkann es tun :).
Sobrique
Vielen Dank! Die Antwort von Stéphane Chazelas kommt meiner Frage etwas näher (da ich Perl nicht installiert habe - vermutlich ein Du * B-Windows-Benutzer), weshalb ich seine Antwort akzeptierte.
bers
Das ist in Ordnung - aber ich würde empfehlen, Perl unter Windows zu installieren. Es ist eines der ersten Dinge, die mir passieren, und ich finde es äußerst hilfreich.
Sobrique
\wwar in GNU grep (in den 80ern) bevor ich in Perl war und in GNU emacs wahrscheinlich sogar vorher.
Stéphane Chazelas
1

Ich vermute das grepund sedentscheide unterschiedlich, wann die anzuwenden []und wann die zu erweitern sind \w. In Perl \wbedeutet Regex ein beliebiges Wortzeichen und []definiert eine Gruppe, um eines der Zeichen als Übereinstimmung anzuwenden. Wenn Sie das \wvor dem "erweitern" [], wird es eine Zeichenklasse aller Wortzeichen sein. Wenn stattdessen tun Sie []zuerst finden Sie eine Zeichenklasse mit zwei Zeichen lang sein \und wso wäre es irgendein Muster entsprechen , die eine oder mehrere dieser beiden Zeichen.

Es sedsieht also so aus, als würde das []und behandelt es so, als würde es die exakten Zeichen enthalten, die übereinstimmen, anstatt die spezielle Sequenz \wwie perlund zu grepbeachten. Natürlich []sind die in diesem Beispiel völlig unnötig, aber man könnte sich vielleicht Fälle vorstellen, in denen es wichtig wäre, aber dann könnten Sie dafür sorgen, dass es mit parens und ors funktioniert.

Eric Renouf
quelle
Ich wäre überrascht, wenn das so wäre. \ ist ein Escape-Code, und Sie würden ihn verwenden, um Begrenzer zu maskieren. Inhärent bedeutet dies, dass es eine höhere Priorität haben muss als alles andere. Ich denke, es ist wahrscheinlicher, dass es nicht implementiert wird, weil \wes nicht Teil der Spezifikation für reguläre Ausdrücke ist
Sobrique
Nun, empirisch scheint es der Fall zu sein, wenn echo whe\\ere | sed -r 's/[\w]+/gone/gich Gnused benutze: Gib mir, gonehegoneereals würde es zu jedem der ` and W passen und die Substitution machen
Eric Renouf
Ich kann bestätigen, was Eric Renouf sieht. Also wollen wir dem Backslash irgendwie entkommen? :)
bers
Ich denke nicht, dass das die richtige Antwort ist. Sed unterstützt nur nicht das Mischen der verschiedenen Arten von Zeichenklassendefinitionen. Daher lautet die Antwort, wenn Sie beide Arten von Zeichenklassen verwenden müssen, wählen Sie ein anderes Werkzeug aus, oder wenn Sie sed auswählen, verwenden Sie die von ihm unterstützte Syntax.
Eric Renouf