Jak wyodrębnić tekst z ciągu za pomocą seda?


98

Mój przykładowy ciąg jest następujący:

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

Teraz z powyższego ciągu chcę wyodrębnić 02G05. W tym celu wypróbowałem następujące wyrażenie regularne z sed

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

Ale powyższe polecenie nic nie drukuje i uważam, że nie jest w stanie dopasować niczego do wzorca, który dostarczyłem sedowi.

Więc moje pytanie brzmi: co robię źle i jak to poprawić.

Kiedy próbuję powyższego ciągu i wzoru w Pythonie, otrzymuję wynik

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

6
Python zdecydowanie nie jest sed. Ich smaki regex są zupełnie inne.
tripleee

Odpowiedzi:


96

Wzorzec \dmoże nie być obsługiwany przez sed. Spróbuj [0-9]lub [[:digit:]]zamiast tego.

Aby wydrukować tylko rzeczywiste dopasowanie (a nie całą pasującą linię), użyj podstawienia.

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

6
Dzięki, działało dobrze. Ale mam pytanie, dlaczego .*jest to konieczne z twoim wyrażeniem regularnym, ponieważ kiedy próbuję sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p', po prostu drukuje cały wiersz.
RanRag,

7
Dlatego, prawda? Zastąp wszystko, co pojawi się przed i po dopasowaniu, na norhing, a następnie wydrukuj całą linię.
tripleee

1
@tripleee To tylko 2G05nie drukuje 02G05. Wyrażenie, które działa, to's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma

1
To sztywno koduje go na dokładnie dwie cyfry. Coś takiego sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'byłoby bardziej ogólne. (Zakładam swoje sedwsporniki \?do zera lub jednego wystąpienia.)
tripleee

Zobacz także stackoverflow.com/a/48898886/874188 na sposób wymiany różnych innych wspólnych ucieka jak Perl \w, \sitp
tripleee

102

A co powiesz na używanie grep -E?

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

3
+1 Jest to prostsze i będzie również poprawnie obsługiwać przypadek wielu dopasowań w tej samej linii. sedMożna by opracować złożony scenariusz dla tego przypadku, ale po co się tym przejmować?
tripleee

egrepużywa rozszerzonego wyrażenia regularnego sedi grepużywa standardowego wyrażenia regularnego egreplub grep -elub sed -Erozszerzonego wyrażenia regularnego, a kod Pythona w pytaniu używa PCRE, (typowe wyrażenie regularne perla) GNU grep może używać PCRE z -Popcją.
Felipe Buccioni

@FelipeBuccioni właściwie to powinno być egreplub grep -Elubsed -r
SensorSmith

Dla pojedynczego (pierwszego) dopasowania dodaj `| głowa -1` (bez grawitacji), zgodnie z tą odpowiedzią na inne pytanie.
SensorSmith

1
grepmusi -m 1się zatrzymać po pierwszym meczu.
tripleee


5

Spróbuj tego zamiast tego:

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

Ale zwróć uwagę, że jeśli w jednym wierszu znajdują się dwa wzory, drukuje drugi.


Lub bardziej ogólnie ostatni, jeśli jest wiele dopasowań.
tripleee

0

Spróbuj użyć rextract . Pozwoli ci to wyodrębnić tekst za pomocą wyrażenia regularnego i sformatować go.

Przykład:

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

2G05

Jeśli używa standardowego wyrażenia regularnego, nawiasy kwadratowe wokół \dsą całkowicie zbędne.
tripleee
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.