Zeichenfolge vor Zahlen und nach Unterstrich extrahieren

Zeichenfolge vor Zahlen und nach Unterstrich extrahieren

Die ursprüngliche Zeichenfolge lautet wie folgt:

str-str001-002_01
str-str005-006_05

Ich möchte den String vor der Zahl und nach dem Unterstrich extrahieren, also sähe es folgendermaßen aus:

str-str_01
str-str_05

Ich erinnere mich, dass sed Muster wie folgt in Gruppen aufteilen konnte:

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

aber es druckt:

str-str0002_01

Dann fällt mir ein, dass [0-9] nur eine Zahl ist, also habe ich es mit dem Pluszeichen oder dem Sternchen probiert. Das Ergebnis war leer.

ps: durch die Verwendung

echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'

Ich sehe, dass es passt 1-0.

Dann habe ich es versucht mit:

echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'

Es blieben die ersten beiden Zahlen übrig und es stimmt nur überein

1-002

also wie bringt man es zusammen001-002

Antwort1

Dies liefert die erforderliche Ausgabe:

sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'

Ausgabe aus Ihrem Beispiel

str-str_01
str-str_05

Erläuterung

  • sed -nE 's/…/…/p'- Verwenden Sie EREs, drucken Sie keine Zeilen, wenn sie nicht übereinstimmen
  • ^- Anker am Zeilenanfang
  • ([^0-9]*)- ein möglichst langes Muster abgleichen, das mindestens ein Zeichen enthält, das keine Ziffer ist
  • .*_- so viele Übereinstimmungen wie möglich (auch nichts), gefolgt von " _"
  • ([^_]+)- Suche nach einem möglichst langen Muster (mindestens ein Zeichen), das kein Unterstrich ist
  • $- Anker am Ende der Leine
  • \1_\2- Ersetzen Sie die gesamte Zeile durch die erste (…)Übereinstimmung, " _" und die zweite (…)Übereinstimmung

Der Grund, warum Ihre Versuche nicht wie erwartet funktioniert haben, ist, dass *(und +) gierig ist – es verbraucht so viele Zeichen wie möglich, die mit dem vorhergehenden Atom übereinstimmen. Wenn also ein ERE von (.*)([0-9]+)auf etwas wie angewendet wird abc123, .* verbraucht das abc12, sodass [0-9]+nur noch mit übereinstimmt 3. Sie benötigen ein „keine Ziffer" um die erste Übereinstimmung einzuschränken: ([^0-9]*)([0-9]+)um abcund zu erhalten 123.

Antwort2

$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05

Der Ersetzungsbefehl hier gleicht ab und entfernt, NNN-NNNwobei es NNNsich um eine Folge von drei Ziffern handelt.

Passenmindestens einZiffer, verwenden Sie 1,anstelle von 3:

$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05

Dies entspricht der Verwendung in einem erweiterten regulären Ausdruck. Die von standardmäßig +verwendeten regulären Ausdrücke sind „einfache“ reguläre Ausdrücke und würden einem wörtlichen Pluszeichen entsprechen. Die meisten Implementierungen unterstützen auch erweiterte Ausdrücke mit :sed+sed-E

$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05

Die Verwendung von *, wie in , würde nicht funktionieren, da dies dem Bindestrich in (der von null Ziffern umgeben ist) [0-9]*-[0-9]*entsprechen würde .str-str


Wenn Sie das Gefühl haben, dass Sie wirklich die ganze Zeile abgleichen und die Bits erfassen müssen, die Sie behalten möchten, können Sie dies auch tun. Der folgende Befehl erfasst die anfänglichen Nicht-Ziffern und das letzte Bit, einschließlich des Unterstrichs:

$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05

Dies ist meiner Meinung nach jedoch etwas schwierig zu entziffern und macht Annahmen über den Anfang und das Ende der Zeichenfolge, die Sie in der Frage nie erwähnt haben. Der Anfang kann beispielsweise keine Ziffern vor den Ziffern enthalten, die Sie entfernen möchten, und das Ende der Zeichenfolge wird an derzuletztUnterstrich, nicht unbedingt nach den Ziffern, die Sie entfernen möchten, wenn in diesem Teil der Zeichenfolge mehrere Unterstriche vorhanden sind.

Sie könnten diesen Ausdruck jederzeit um weitere Elemente ergänzen, um sicherzustellen, dass nur das NNN-NNNBit nicht erfasst wird. Dadurch würde es jedoch noch schwieriger, den Ausdruck zu verstehen.

verwandte Informationen