grupy przechwytywania sed nie działają


27

Mam ciąg formatu [0-9]+\.[0-9]+\.[0-9]. Muszę wyodrębnić pierwszą, drugą i trzecią liczbę osobno. Jak rozumiem, grupy przechwytywania powinny mieć taką możliwość. Powinienem być w stanie użyć sed "s/\([0-9]*\)/\1/gpierwszego numeru, sed "s/\([0-9]*\)/\2/gdrugiego numeru i sed "s/\([0-9]*\)/\3/gtrzeciego numeru. Jednak w każdym przypadku otrzymuję cały ciąg. Dlaczego to się dzieje?


6
Grupy przechwytywania przechwytują całą grupę ... a nie poszczególne elementy w grupie. Potrzebujesz czegoś, jak 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'uchwycić poszczególne liczby.
Munir

Odpowiedzi:


45

Nie możemy dać ci pełnej odpowiedzi bez przykładu twojego wkładu, ale mogę powiedzieć, że twoje rozumienie grup przechwytywania jest błędne. Nie używasz ich sekwencyjnie, odnoszą się one tylko do wyrażenia regularnego po lewej stronie tego samego operatora podstawienia. Jeśli na przykład przechwycisz, /(foo)(bar)(baz)/wtedy foobędzie \1, barbędzie \2i bazbędzie \3. Nie możesz tego zrobić s/(foo)/\1/; s/(bar)/\2/, ponieważ w drugim s///połączeniu jest tylko jedna grupa przechwycona, więc \2nie zostanie zdefiniowana.

Aby przechwycić trzy grupy cyfr, musisz zrobić:

sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'

Lub, bardziej czytelny:

sed -E 's/([0-9]*)\.([0-9]*)\.([0-9]*)/\1 : \2 : \3/'

1
Jaka jest korzyść z unikania nawiasów w pierwszym przykładzie?
Josh M.

2
@JoshM. musisz uciec od nich, aby mogły zostać wykorzystane do przechwytywania wzorów. Normalnie /(foo)/w sed będzie pasować dosłowny (znak, a foonastępnie literał ). Jeśli chcesz przechwycić grupę, musisz uciec z nawiasów lub skorzystać z -Eopcji.
terdon

Prawie zawsze używam -rflagi, więc zakładam, że dlatego na to nie wpadłem.
Josh M.,

1
@JoshM. tak, -rflaga to zrobi, ale nie jest przenośna. GNU sed obsługuje to, ale wiele innych nie. -EJest bardziej uniwersalna.
terdon

9

Przykład:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'
123

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'
456

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'
78

Lub wszystkie razem:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'
123 : 456 : 78

2

Użyj Sed z opcją -r, --regexp-Extended, aby uniknąć wszystkich nawiasów, których nie można uniknąć

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
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.