Wie extrahiere ich Text aus einem String mit sed?


95

Meine Beispielzeichenfolge lautet wie folgt:

This is 02G05 a test string 20-Jul-2012

Nun möchte ich aus der obigen Zeichenfolge extrahieren 02G05. Dafür habe ich den folgenden Regex mit sed ausprobiert

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

Aber der obige Befehl gibt nichts aus und der Grund, den ich glaube, ist, dass er nichts mit dem Muster vergleichen kann, das ich sed geliefert habe.

Meine Frage ist also, was ich hier falsch mache und wie ich es korrigieren kann.

Wenn ich die obige Zeichenfolge und das obige Muster mit Python ausprobiere, erhalte ich mein Ergebnis

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
Python ist definitiv nicht sed. Ihre Regex-Aromen sind sehr unterschiedlich.
Tripleee

Antworten:


90

Das Muster wird \dmöglicherweise von Ihrem nicht unterstützt sed. Versuchen Sie es [0-9]oder [[:digit:]]stattdessen.

Verwenden Sie eine Ersetzung, um nur die tatsächliche Übereinstimmung (nicht die gesamte übereinstimmende Zeile) zu drucken.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
Danke, es hat gut funktioniert. Aber ich habe eine Frage, warum .*dies bei Ihrer Regex notwendig ist, denn wenn ich es versuche sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p', wird nur die gesamte Zeile gedruckt.
RanRag

7
Das ist der Grund, nicht wahr? Ersetzen Sie alles, was vor und nach dem Match kommt, durch nichts und drucken Sie dann die gesamte Zeile.
Tripleee

1
@tripleee Dies druckt nur 2G05nicht 02G05. Der Ausdruck, der funktioniert, ist's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma

1
Das codiert es genau auf zwei Ziffern. So etwas sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'wäre allgemeiner. (Ich nehme an, Ihre sedUnterstützung \?für null oder ein Vorkommen.)
Tripleee

Siehe auch stackoverflow.com/a/48898886/874188 dafür , wie verschiedene andere gemeinsame ersetzen Perl entkommt wie \w, \setc.
tripleee

98

Wie wäre es mit grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 Dies ist einfacher und behandelt auch den Fall mehrerer Übereinstimmungen in derselben Zeile korrekt. sedFür diesen Fall könnte ein komplexes Skript entwickelt werden, aber warum sollte man sich die Mühe machen?
Tripleee

egrepverwendet Extended Regexp sedund grepverwendet Standard Regexp egrepoder grep -eoder sed -EExtended Regexp, und der Python-Code in der Frage verwendet PCRE (Perl Common Regular Expression). GNU grep kann PCRE mit -POption verwenden.
Felipe Buccioni

@FelipeBuccioni eigentlich sollte das sein egrepoder grep -Eodersed -r
SensorSmith

Fügen Sie für eine einzelne (erste) Übereinstimmung `| hinzu Kopf -1` (ohne Backticks), gemäß dieser Antwort auf eine andere Frage.
SensorSmith

1
grepmuss -m 1nach dem ersten Spiel aufhören.
Tripleee


5

Versuchen Sie stattdessen Folgendes:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

Beachten Sie jedoch, dass bei einer Zeile mit zwei Mustern das zweite gedruckt wird.


Oder allgemeiner die letzte, wenn es mehrere Übereinstimmungen gibt.
Tripleee

0

Versuchen Sie es mit rextract . Sie können Text mit einem regulären Ausdruck extrahieren und neu formatieren.

Beispiel:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05

Wenn hierfür Standard-Regex verwendet wird, sind die eckigen Klammern \dvöllig überflüssig.
Tripleee
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.