sed yakalama grupları çalışmıyor


27

Biçimin bir dizesi var [0-9]+\.[0-9]+\.[0-9]. Birinci, ikinci ve üçüncü sayıları ayrı ayrı çıkarmam gerekiyor. Anladığım kadarıyla, yakalama grupları bunu yapabilmelidir. Kullanmak gerekir sed "s/\([0-9]*\)/\1/g, ilk sayı elde etmek sed "s/\([0-9]*\)/\2/gikinci numarası almak ve sed "s/\([0-9]*\)/\3/güçüncü sayısını almak için. Her durumda, tüm dizeyi alıyorum. Bu neden oluyor?


6
Yakalama grupları, gruptaki öğeleri değil tüm grubu yakalar. 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'Bireysel sayıları yakalamak gibi bir şeye ihtiyacınız var .
Munir

Yanıtlar:


45

Girdilerinize bir örnek olmadan size tam bir cevap veremeyiz, ancak yakalama grupları anlayışınızın yanlış olduğunu söyleyebilirim. Bunları sırayla kullanmazsınız, yalnızca aynı ikame operatörünün sol tarafındaki regex'i ifade ederler. Yakalamak ise, örneğin, /(foo)(bar)(baz)/daha sonra fooolacak \1, barolacak \2ve bazolacak \3. Yapamazsınız s/(foo)/\1/; s/(bar)/\2/, çünkü ikinci s///çağrıda sadece bir tane yakalanan grup var, bu yüzden \2tanımlanmayacak.

Bu nedenle, üç basamak grubunuzu yakalamak için yapmanız gerekenler:

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

Veya daha okunaklı:

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

1
İlk örnekte parantezlerden kaçmanın faydası nedir?
Josh M.

3
@JoshM. desen yakalamak için kullanılmaları için onlardan kaçmanız gerekir. Normalde /(foo)/sed'de değişmez bir (karakterle foove ardından değişmez bir karakterle eşleşir ). Bir grup yakalamak istiyorsanız, parantezlerden kaçmanız veya -Eseçeneği kullanmanız gerekir .
terdon

Neredeyse her zaman -rbayrağı kullanıyorum, bu yüzden bu yüzden henüz buna girmedim.
Josh

1
@JoshM. evet, -rbayrak da bunu yapacak, ama taşınabilir değil. GNU sed bunu destekliyor ama diğerleri desteklemiyor. -EDaha evrenseldir.
terdon

9

Misal:

$ 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

Veya hep birlikte:

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

2

Tüm kaçan parantezleri önlemek için Sed'i -r, --regexp-expand ile kullanın.

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.