çözüm:
echo 'foo_abc_bar' | sed -r 's/(foo)_((abc)_)?(bar)/\1=\3=\4/g'
Neden önceki girişimleri işe yaramadı: eşleşecek teşebbüs regex (foo).*(abc)?.*(bar)
için 'foo_abc_bar'
(foo)
'foo'
maç olacak böylece
.*
, açgözlü, ve daha sonra .*
başlangıçta dizenin geri kalanıyla eşleşecektir ('_abc_bar'
). Regex gerekli (bar)
grubuna ulaşana kadar devam eder ve bu başarısız olur, bu noktada regex .*
tarafından eşleştirilen karakterleri bırakarak geri dönecektir. Bu, ilk .*
yalnızca '_abc_'
ile eşleşene kadar gerçekleşecek, bu noktada son grup 'bar'
ile eşleşecektir. Yani, yakalama grubundaki eşleşen dizideki 'abc'
yerine, .*
yakalamada eşleşir. Benim çözümün
Açıklama:
ilk ve en önemli şey _
ile .*
yerini alacak, sen ayırıcı ne olacağını biliyorsanız rasgele herhangi bir dize maç için gerek yoktur. Yapmamız gereken bir sonraki şey, dizenin hangi kısmının isteğe bağlı olduğunu bulmaktır. 'foo_abc_bar'
ve 'foo_bar'
dizeleri geçerliyse, ortadaki 'abc_'
isteğe bağlıdır. Bunu (abc_)?
kullanarak isteğe bağlı bir gruba koyabiliriz. Son adım, 'abc'
dizgisini hala yakaladığımız bir grupta, bu bölümü ek bir grupta sararak yapabileceğimizden emin olmaktır, böylece ((abc)_)?
ile son buluruz. Daha sonra yedek grubu ayarlamamız gerekiyor çünkü fazladan bir grup var, bu yüzden \1=\3=\4
, \2
'abc_'
(eşleşiyorsa) dize olacaktır. Çoğu regex uygulamasında, yakalama yapmayan bir grubu da kullanabileceğinizi ve \1=\2=\3
'u kullanmaya devam edebileceğinizi, ancak sed'in yakalamayan grupları desteklemediğini unutmayın.
Alternatif:
Ben (sadece ilgilendiğiniz tam dizeleri maç olacak) en açık olduğu için regex yukarıdaki en iyi bahis olduğunu düşünüyorum. Ancak, yukarıda açıklandığı gibi, tembel tekrarlama yerine (mümkün olduğunca çok karakterle eşleşir) tembel tekrarlama (olabildiğince az karakter eşleşmesi) kullanarak da önlenebilir.
echo 'foo_abc_bar' | sed -r 's/(foo).*?(abc).*?(bar)/\1=\2=\3/g'
Neden ifadede '. *' Kullanıyorsunuz, altçizgi herhangi bir rastgele dizeyle değiştirilebilir mi? –