Bagaimana cara mengganti karakter dengan sed secara rekursif?

13

Apakah mungkin untuk mengganti kemunculan urutan karakter secara rekursif tanpa mengulangi urutan yang sama lagi?

Dengan melakukan sedseperti pada skenario berikut saya bisa mendapatkan output yang disebutkan.

$ 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  

Namun, saya mengharapkan output mengikuti perilaku berikut.

Memasukkan:

XX
XXX
XXXX

Output yang diharapkan:

XoX
XoXoX
XoXoXoX

Apakah mungkin untuk mencapai perilaku yang diharapkan dengan sed saja?

Ishan Madhusanka
sumber

Jawaban:

24

Anda dapat melakukan:

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

Dengan:

  • -e ':loop' : Buat label "loop"
  • -e 't loop' : Lompat ke label "loop" jika penggantian sebelumnya berhasil
Gohu
sumber
10

Dalam kasus khusus ini, melihat ke depan atau melihat ke belakang akan bermanfaat. Saya pikir GNU sedtidak mendukung ini. Dengan perl:

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

Anda juga dapat menggunakan lookbehind dan lookahead seperti:

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

Dimana:

(?<=X)adalah tampilan positif di belakang, pernyataan panjang nol yang memastikan kami memiliki tanda X sebelum posisi saat ini
(?=X)adalah pandangan positif, pernyataan panjang nol yang memastikan kami memiliki tanda X setelah posisi saat ini

Menggunakan dalam perl one-liner:

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

Dimana:

-p menyebabkan Perl untuk menganggap loop di sekitar program dengan cetakan implisit dari baris saat ini

Toto
sumber
5

Jawaban perulangan adalah cara umum untuk melakukan apa yang Anda minta.

Namun dalam hal data Anda, dengan asumsi Anda menggunakan GNU, Anda bisa melakukannya:

sed 's/\B/o/g'

The \bdan \Bpilihan adalah ekstensi regex :

  • \b cocok dengan batas kata, yaitu transisi dari karakter "kata" ke karakter "non-kata", atau sebaliknya
  • \Bcocok dengan kebalikan dari \b. yaitu kesenjangan "di dalam" kata-kata. Ini memungkinkan kami untuk memasukkan karakter ke dalam kata tetapi tidak di luar, seperti yang diperlukan.

Cobalah online .

Ini mengasumsikan bahwa karakter input sebenarnya semua karakter "kata".


Atau jika Anda tidak memiliki GNU sed, atau jika karakter input tidak semua karakter "kata", Anda masih dapat mencapai tujuan Anda tanpa mengulang:

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

Ini cukup tempat osetelah setiap karakter dan kemudian menghapus final odari string.

Cobalah online .

Trauma Digital
sumber
1
Ini mengasumsikan bahwa string input terdiri dari sejumlah Xdan tidak ada yang lain. Kedua solusi gagal jika ada karakter lain yang hadir ...
AnoE
@AnoE Dalam sampel kedua, yang diperbaiki dengan penggantian sederhana Xoleh .. Silakan lihat edit.
Digital Trauma
Tidak setara dengan kasus yang OP berikan. Dia memberikan RE tepat yang dia butuhkan (mengubah kejadian XX dalam sebuah string). Versi Anda hanya memberikan hasil yang sama dengan miliknya untuk string input yang sama persis yang ia berikan; bukan untuk string input umum.
AnoE
4

Saya memeriksa apakah ada semacam bendera untuk mewujudkannya.
Bahkan jika perilaku itu ada di sana, itu akan memakan banyak sumber daya.

Namun, dalam kasus penggunaan khusus ini, dimungkinkan untuk memiliki ekspresi hanya dua kali dan mencapai fungsionalitas yang diperlukan. yaitu dengan 2 sedekspresi berulang .

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
Ishan Madhusanka
sumber