Bagaimana cara mengganti konten antara dua pola dari file?

9

Saya memiliki format file berikut:

<common>
fitnes=0
genetic=1
method=0
</common>
<inputs>
foo=bar
bar=foo
</inputs>
<limits>
balance=200.00
</limits>

dan saya ingin menghapus semua yang ada di antara <inputs>dan </inputs>(tidak termasuk pola itu sendiri) dan menggantinya dengan konten dari file lain (misalnya foo.txt). Dengan kata lain baris dengan foo=bardan bar=fooakan diganti dengan konten lain.

Mungkin bisa mirip dengan cara Anda menghapus kecocokan multi-garis , seperti:

:g/<inputs/,/inputs>/d

tapi saya tidak yakin dengan apa yang harus saya ganti duntuk memasukkan konten file lain, tetapi saya ingin mempertahankan pola yang cocok.

Pendekatan serupa akan menghapus konten dalam dari tag html , seperti

:/<inputs>/norm vitd

tapi kemudian saya tidak tahu bagaimana Anda menambahkan konten dari file tersebut.

Idealnya saya mencoba menemukan satu liner, karena itu akan menjadi bagian dari skrip lain.

Bagaimana saya bisa mencapainya?

kenorb
sumber

Jawaban:

10

Substitusi dapat digunakan untuk mengganti pola dengan hasil ekspresi seperti ini:

:keeppatterns %s;<inputs>\zs\_.\{-}\ze</inputs>;\=insert(readfile('test.txt'), '')

Lihat :help sub-replace-expression

Catatan yang keeppatternsmencegah substituteperintah menambahkan apa pun ke riwayat pencarian dan mempertahankan "register pola pencarian terakhir" - lihat :help "/. Ini praktik yang baik untuk mencegah script dari tidak perlu memodifikasi negara global Vim dengan pengubah perintah keepalt, keepjumps, lockmarks, keepmarks, dan keeppatterns.

djjcast
sumber
5

Pendekatan alternatif untuk itu dari Gary adalah ini:

:g/^<inputs>/+,/^<\/inputs>/-d|-r dummy

Yang pertama menghapus segala sesuatu dalam pola yang diberikan, daripada menggunakan :rperintah untuk membaca data dari file dummy. Sekarang jika Anda perlu mengekstrak nama file dari garis-garis di antara <input>/</input>pola, itu akan sedikit lebih rumit.

Christian Brabandt
sumber
4

Ini tampaknya berhasil, setidaknya pada sistem Unix:

:/<inputs>/+1,/<\/inputs>/-1!cat foo.txt

Ia menggunakan {range}!{filter}perintah untuk menyaring garis dari satu <inputs>ke satu sebelum </inputs>melalui program eksternal cat foo.txt. Dalam hal ini, catabaikan input standarnya, sehingga baris asli dihapus dan diganti dengan isi file foo.txt.

Lihat:

:help :range!
:help cmdline-ranges
garyjohn
sumber
2

Saya merasa makro akan menjadi pendekatan yang lebih mudah. Terutama, jika Anda memiliki berbagai tempat untuk melakukan hal yang sama.

  1. Biarkan hanya 2 file itu tetap terbuka.
  2. Sekarang dalam file pertama mulai merekam dengan qa,( aadalah nama rekaman).
  3. Cari pola awal, tekan ke bawah , lalu tekan Ctrl- v, cari pola akhir, tekan ke atas . Sekarang bagian yang ingin Anda hapus dipilih. Hapus.
  4. Tandai posisi menggunakan ma( aadalah nama tanda) dan simpan file.
  5. Pergi ke file ke-2, dengan :b2perintah dan pilih bagian yang sama sesuai dengan kriteria awal / akhir Anda.
  6. Kembali ke file ini, tekan auntuk pergi ke titik itu. Tempel di sana p.
  7. Cari kriteria akhir lagi, dan lintas bagian untuk tidak memukulnya lagi.
  8. Berhenti pengodean ulang dengan menekan q.
  9. Ulangi berapa kali dengan 40@a.
Krishanu Banerjee
sumber
1
Terima kasih atas sarannya, tidak apa-apa, tetapi tidak akan membantu dalam kasus khusus ini, karena saya sedang mencari solusi non-interaktif sebagai bagian dari exskrip di mana saya dapat menentukan file mana yang akan dimasukkan tergantung pada argumen input pengguna.
kenorb
1

Jika ini merupakan upaya lain untuk mem-parsing XML dengan Alat non-XML, jangan.

Solusi di sini valid, tetapi niatnya mungkin tidak. Jika XML bukan dari sumber yang dijinakkan dengan baik, Anda mungkin mendapatkan escapes, CDATA, atau spasi putih di tag!

Jadi xsltproc dari command in vi dapat mengatasinya.

Matthias Š
sumber
File tersebut sebenarnya bukan format XML yang tepat, tetapi sebenarnya inifile tersebut tidak terdokumentasi dengan baik menggunakan 3 tag mirip XML itu.
kenorb