512 Stimmen

Nicht gieriger (zurückhaltender) Regex-Abgleich in sed?

Ich versuche, sed zu verwenden, um Zeilen von URLs zu bereinigen, um nur die Domain zu extrahieren.

Also von:

http://www.suepearson.co.uk/product/174/71/3816/

Ich will:

http://www.suepearson.co.uk/

(entweder mit oder ohne den abschließenden Schrägstrich, es spielt keine Rolle)

Ich habe es versucht:

 sed 's|\(http:\/\/.*?\/\).*|\1|'

und (unter Auslassung des nicht-gierigen Quantors)

sed 's|\(http:\/\/.*\?\/\).*|\1|'

aber ich scheine den nicht-gierigen Quantifizierer nicht zu bekommen ( ? ), um zu funktionieren, so dass am Ende immer die ganze Zeichenfolge übereinstimmt.

68 Stimmen

Eine Randbemerkung: Wenn Sie Ihre Regexe mit "|" abgrenzen, brauchen Sie die "/"s nicht zu escapen. Tatsächlich grenzen die meisten Leute mit "|" anstelle von "/" ab, um die "Zäune" zu vermeiden.

15 Stimmen

@AttishOculus Das erste Zeichen nach dem 's' in einem Ersatzausdruck in sed ist das Trennzeichen. Daher funktionieren auch 's^foo^bar^' oder 's!foo!bar!'

1 Stimmen

Für erweiterte Regex, verwenden Sie sed -E 's... . Dennoch, kein unwilliger Betreiber.

521voto

chaos Punkte 118918

Weder der einfache noch der erweiterte Posix/GNU-Regex erkennt den Non-Greedy-Quantifizierer; Sie benötigen einen späteren Regex. Glücklicherweise ist Perl Regex für diesen Kontext ziemlich einfach zu bekommen:

perl -pe 's|(http://.*?/).*|\1|'

20 Stimmen

Für die Durchführung an Ort und Stelle verwenden Sie die Optionen -pi -e .

16 Stimmen

Heiliger Strohsack, ich kann nicht glauben, dass das funktioniert hat :-) Das Einzige, was nervt, ist, dass mein Skript jetzt eine Perl-Abhängigkeit hat :-( Auf der anderen Seite hat praktisch jede Linux-Distribution bereits Perl, also wahrscheinlich kein Problem :-)

10 Stimmen

@Freedom_Ben: IIRC perl es erforderlich durch POSIX

41voto

andcoz Punkte 2192

Sed unterstützt keine "non greedy" Operatoren.

Sie müssen den "[]"-Operator verwenden, um "/" vom Treffer auszuschließen.

sed 's,\(http://[^/]*\)/.*,\1,'

P.S. Der Backslash "/" ist nicht erforderlich.

0 Stimmen

Nicht wirklich. Wenn das Trennzeichen eines von vielen möglichen Zeichen sein könnte (z. B. nur eine Zahlenkette), könnte Ihre Negationsübereinstimmung immer komplexer werden. Das ist in Ordnung, aber es wäre sicherlich nett, eine Option zu haben, um .* nicht gierig zu machen

1 Stimmen

Die Frage war eher allgemein gehalten. Diese Lösungen funktionieren für URLs, aber nicht (z. B.) für meinen Anwendungsfall des Entfernens von Nullen am Ende. s/([[:digit:]]\.[[1-9]]*)0*/\1/ würde offensichtlich nicht gut funktionieren für 1.20300 . Da sich die ursprüngliche Frage jedoch auf URLs bezog, sollten diese in der akzeptierten Antwort erwähnt werden.

25voto

gresolio Punkte 950

sed - non greedy matching von Christoph Sieghart

Der Trick, um eine nicht gierige Übereinstimmung in sed zu erhalten, besteht darin, alle Zeichen mit Ausnahme des Zeichens, das die Übereinstimmung beendet, abzugleichen. Ich weiß, ein No-Brainer, aber ich habe wertvolle Minuten damit verschwendet, und Shell-Skripte sollten schließlich schnell und einfach sein. Für den Fall, dass jemand anderes es brauchen könnte:

Gieriger Abgleich

% echo "<b>foo</b>bar" | sed 's/<.*>//g'
bar

Nicht gieriger Abgleich

% echo "<b>foo</b>bar" | sed 's/<[^>]*>//g'
foobar

17voto

Dee Punkte 179

Dies kann durch Ausschneiden geschehen:

echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3

9voto

ghostdog74 Punkte 305138

Eine andere Möglichkeit, ohne Regex, ist die Verwendung der Methode Felder/Trennzeichen, z. B.

string="http://www.suepearson.co.uk/product/174/71/3816/"
echo $string | awk -F"/" '{print $1,$2,$3}' OFS="/"

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X