Karakterleri yinelemeli olarak sed ile nasıl değiştirebilirim?


13

Aynı dizinin tekrarını tekrarlamadan bir karakter dizisinin oluşumlarını yinelemeli olarak değiştirmek mümkün müdür?

Bir gerçekleştirerek sedaşağıdaki senaryolarda olarak bahsettiğim çıktı alabilirsiniz.

$ echo XX | sed -e 's/XX/XoX/g'
XoX  
$ echo XXX | sed -e 's/XX/XoX/g'
XoXX  
$ echo XXXX | sed -e 's/XX/XoX/g'
XoXXoX  

Ancak, çıktının aşağıdaki davranışı izlemesini bekliyorum.

Giriş:

XX
XXX
XXXX

Beklenen çıktı:

XoX
XoXoX
XoXoXoX

Yalnızca sed ile beklenen davranışı elde etmek mümkün mü?

Yanıtlar:


24

Yapabilirsin:

> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX

İle:

  • -e ':loop' : "Döngü" etiketi oluşturma
  • -e 't loop' : Önceki değiştirme başarılı olduysa "döngü" etiketine atla

10

Bu özel durumda ileriye bakma ya da geriye bakma faydalı olacaktır. Bence GNU sedbunları desteklemiyor. İle perl:

perl -ne 's/X(?=X)/Xo/g; print;'

Ayrıca lookbehind ve lookahead komutunu aşağıdaki gibi kullanabilirsiniz:

s/(?<=X)(?=X)/o/g

Nerede:

(?<=X)
(?=X)olumlu bir bakış, mevcut konumdan önce bir X'e sahip olduğumuzdan emin olan sıfır uzunluklu bir iddiadır, geçerli bir konumdan önce bir X'e sahip olduğumuzdan emin olunan sıfır uzunlukta bir iddiadır.

Perl bir astarda kullanma:

perl -pe 's/(?<=X)(?=X)/o/g' inputfile

Nerede:

-p Perl'in programın etrafında geçerli satırın örtülü baskısıyla bir döngü oluşturmasına neden olur


5

Döngüsel cevap, sorduğunuz şeyi yapmanın genel yoludur.

Ancak verilerinizde GNU kullandığınızı varsayarsak şunları yapabilirsiniz:

sed 's/\B/o/g'

\bVe \Bseçenekler regex uzantıları :

  • \b kelime sınırlarıyla eşleşir, yani bir "kelime" karakterinden "kelime olmayan" karaktere geçiş veya tam tersi
  • \Bile tam tersi eşleşir \b. yani "iç" kelimelerin boşlukları. Bu, bir sözcüğün içine karakterler eklememize izin verir, ancak gerektiğinde dışarıda değil.

Çevrimiçi deneyin .

Bu, giriş karakterlerinin aslında tüm "kelime" karakterleri olduğunu varsayar.


Alternatif olarak GNU sed'iniz yoksa veya giriş karakterlerinin tümü "kelime" karakterleri değilse, yine de döngüye girmeden hedefinize ulaşabilirsiniz:

sed 's/./&o/g;s/o$//'

Bu, oher karakterden sonra bir son ekler ve sonuncuyu odizeden kaldırır .

Çevrimiçi deneyin .


1
Bu, girdi dizelerinin bazı sayılardan oluştuğunu Xve başka bir şey olmadığını varsayar . Başka karakterler de varsa her iki çözüm de başarısız olur ...
AnoE

@AnoE olarak basit bir değiştirme ile tespit edilir, ikinci numune, Xtarafından .. Lütfen düzenlemeye bakın.
Dijital Travma

OP'nin verdiği davaya eşdeğer değil. İhtiyaç duyduğu kesin RE'leri verdi (dizede XX oluşumlarını değiştir). Sürümleriniz yalnızca verdiği aynı giriş dizeleriyle aynı sonucu verir; genel giriş dizeleri için değil.
AnoE

4

Bunun gerçekleşmesi için herhangi bir bayrak olup olmadığını kontrol ettim.
Bu davranış orada olsa bile, son derece kaynak tüketici olacaktır.

Bununla birlikte, bu özel kullanım durumunda, ifadeyi sadece iki kez almak ve gerekli işlevselliği elde etmek mümkündür. yani 2 yinelenen sedifade ile.

echo XX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'     # outputs XoX
echo XXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'    # outputs XoXoX
echo XXXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'   # outputs XoXoXoX
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.