Saya ingin mencari dan mengganti setiap kemunculan pola tertentu dengan angka desimal yang dimulai dengan 1
dan bertambah satu untuk setiap kecocokan.
Saya dapat menemukan pertanyaan dengan kata yang sama yang ternyata bukan tentang menambah penghitung tetapi memodifikasi setiap kecocokan dengan jumlah yang tetap. Pertanyaan serupa lainnya adalah tentang memasukkan nomor baris dan bukan penghitung yang bertambah.
Contoh, sebelum:
#1
#1.25
#1.5
#2
Setelah:
#1
#2
#3
#4
Data saya yang sebenarnya memiliki lebih banyak teks di sekitar hal-hal yang saya ingin nomor ulang.
substitute
hippietrail
sumber
sumber
perldo
, Anda dapat menggunakan:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Jawaban:
Anda perlu substitusi dengan negara. Saya ingat pernah memberikan (/ beberapa?) Solusi lengkap untuk masalah seperti ini pada SO.
Berikut ini cara lain untuk melanjutkan (1). Sekarang, saya akan melanjutkan ke 2 langkah:
Pemberian yang mana:
Jika Anda tidak terbiasa dengan regex, saya menggunakan
:h /\zs
dan\ze
untuk menentukan sub-pola mana yang saya cocok, maka saya cocok dengan serangkaian digit yang mungkin diikuti oleh titik dan angka lainnya. Ini tidak sempurna untuk angka floating point, tetapi ini sudah cukup di sini.Catatan: Anda harus membungkusnya dalam perintah + fungsi pasangan untuk antarmuka yang sederhana. Sekali lagi, ada contoh pada SO / vim (di sini , di sini , di sini ) Saat ini saya cukup tahu vim untuk tidak peduli tentang membungkus trik ini menjadi sebuah perintah. Memang saya akan dapat menulis perintah ini pada percobaan pertama, sementara saya akan mengambil beberapa menit untuk mengingat nama perintah.
(1) Tujuannya adalah untuk dapat mempertahankan keadaan di antara pergantian, dan untuk mengganti kejadian saat ini dengan sesuatu yang tergantung pada keadaan saat ini.
Berkat
:s\=
kami dapat menyisipkan sesuatu yang dihasilkan dari perhitungan.Tetap masalah negara. Baik kita mendefinisikan fungsi yang mengelola keadaan eksternal, atau kita memperbarui diri kita sendiri keadaan eksternal. Dalam C (dan bahasa terkait), kami bisa menggunakan sesuatu seperti
length++
ataulength+=1
. Sayangnya, dalam skrip vim,+=
tidak dapat digunakan di luar kotak. Itu perlu digunakan dengan:set
atau dengan:let
. Ini berarti:let length+=1
menambah angka, tetapi tidak mengembalikan apa pun. Kami tidak bisa menulis:s/pattern/\=(length+=1)
. Kami membutuhkan sesuatu yang lain.Kami membutuhkan fungsi bermutasi. yaitu fungsi yang mengubah inputnya. Kami memiliki
setreg()
,map()
,add()
dan mungkin lebih. Mari kita mulai dengan mereka.setreg()
bermutasi register. Sempurna. Kita bisa menulissetreg('a',@a+1)
seperti pada solusi @Doktor OSwaldo. Namun, ini tidak cukup.setreg()
lebih merupakan prosedur daripada fungsi (bagi mereka yang tahu Pascal, Ada ...). Ini berarti tidak mengembalikan apa pun. Sebenarnya, itu mengembalikan sesuatu. Nominal exit (yaitu pintu keluar non-pengecualian ) selalu mengembalikan sesuatu. Secara default, ketika kami lupa mengembalikan sesuatu, 0 dikembalikan - ini juga berlaku dengan fungsi bawaan . Itu sebabnya dalam solusinya ekspresi pengganti sebenarnya\=@a+setreg(...)
. Tricky, bukan?map()
bisa juga digunakan. Jika kita mulai dari daftar dengan satu 0 (:let single_length=[0]
), kita bisa menambahkannya berkatmap(single_length, 'v:val + 1')
. Maka kita perlu mengembalikan panjang baru. Tidak sepertisetreg()
,map()
mengembalikan input yang dimutasi. Itu sempurna, panjangnya disimpan pada posisi pertama (dan unik, dan juga terakhir) dari daftar. Ekspresi pengganti bisa\=map(...)[0]
.add()
adalah salah satu yang sering saya gunakan karena kebiasaan (saya baru sajamap()
benar - benar tahu, dan saya belum menentukan penampilan masing-masing). Gagasannyaadd()
adalah menggunakan daftar sebagai kondisi saat ini, dan menambahkan sesuatu di akhir sebelum setiap penggantian. Saya sering menyimpan nilai baru di akhir daftar, dan menggunakannya untuk penggantian. Sepertiadd()
juga kembali daftar masukan bermutasi, kita bisa menggunakan:\=add(state, Func(state[-1], submatch(0)))[-1]
. Dalam kasus OP, kita hanya perlu mengingat berapa banyak kecocokan yang terdeteksi sejauh ini. Mengembalikan panjang daftar negara ini sudah cukup. Karena itu saya\=len(add(state, whatever))
.sumber
\=
mengharapkan ekspresi, dan karena tidak seperti C,i+=1
bukanlah sesuatu yang melakukan peningkatan dan mengembalikan ekspresi. Ini berarti bahwa di belakang\=
saya memerlukan sesuatu yang dapat memodifikasi penghitung dan yang mengembalikan ekspresi (sama dengan penghitung itu). Sejauh ini, satu-satunya hal yang saya temukan adalah fungsi manipulasi daftar (dan kamus). @Doktor OSwaldo telah menggunakan fungsi bermutasi lainnya (setreg()
). perbedaannya adalah bahwasetreg()
tidak pernah mengembalikan apa pun, yang berarti selalu mengembalikan nomornya0
.Namun berhati-hatilah, itu akan menimpa register Anda
a
. Saya pikir ini sedikit lebih lurus daripada jawaban luc, tapi mungkin itu lebih cepat. Jika solusi ini entah bagaimana lebih buruk daripada nya, saya akan senang mendengar umpan balik mengapa jawabannya lebih baik. Umpan balik apa pun untuk meningkatkan jawaban akan sangat dihargai!(Ini juga didasarkan pada jawaban SO saya /programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim -edi / 43539546 # 43539546 )
sumber
@a+setreg('a',@a+1)
lebih pendek darilen(add(t,1))
. Kalau tidak, ini adalah trik kotor lain yang bagus :). Saya belum memikirkan yang satu ini. Mengenai penggunaan fungsi kamus yang mutasi dalam teks pengganti, dari:s
dansubstitute()
, saya telah mencatat ini jauh lebih cepat dari loop eksplisit - maka implementasi fungsi daftar saya di lh-vim-lib . Saya kira solusi Anda akan setara dengan saya, mungkin sedikit lebih cepat, saya tidak tahu.@a
tidak dimodifikasi. Dalam skrip, ini adalah IMO penting. Saat dalam mode interaktif, sebagai pengguna akhir, saya akan tahu register mana yang dapat saya gunakan. Messing dengan register kurang penting. Dalam solusi saya, dalam mode interaktif, variabel global kacau; dalam skrip akan menjadi variabel lokal.+3
, saya bisa menulis sesuatu seperti\=add(thelist, 3 + get(thelist, -1, 0))[-1]
.Saya menemukan pertanyaan serupa tetapi berbeda yang saya tanyakan beberapa tahun yang lalu dan berhasil mengubah salah satu jawabannya tanpa sepenuhnya memahami apa yang saya lakukan dan itu berhasil:
Khususnya saya tidak mengerti mengapa saya tidak menggunakan
%
atau mengapa saya hanya menggunakan variabel polos yang jawaban lain hindari karena alasan tertentu.sumber
s//g
pernyataan normal . Pokoknya itu solusi yang menarik. Mungkin @LucHermitte dapat memberi tahu Anda lebih banyak tentang pro dan kontra, karena pengetahuan saya tentang vimscript sangat terbatas dibandingkan dengan itu.printf()
sekalipun - karena Daftar diperkenalkan di Vim 7. Tapi saya harus mengakui bahwa saya tidak akan mengharapkan (/ tidak ingat?)<bar>
Milik ke dalam lingkup:global
- TKI, skenario yang saya harapkan adalah menerapkannya:sub
pada baris yang cocok, lalu bertambahi
satu kali di akhir. Saya berharap solusi ini sedikit lebih lambat. Tetapi apakah itu benar-benar penting? Yang penting adalah seberapa mudah kita bisa datang dengan solusi yang berfungsi dari memori + coba & kesalahan. Misalnya, Vimgolfers lebih suka makro.g/s//
perilaku lingkup memungkinkan untuk trik kotor lainnya. Jadi terima kasih atas jawaban dan diskusi yang menarik, saya tidak sering belajar sebanyak itu dari memberikan jawaban =).Sudah ada tiga jawaban bagus di halaman ini, tetapi, seperti yang disarankan Luc Hermitte dalam komentar , jika Anda melakukan ini, yang penting adalah seberapa cepat dan mudah Anda dapat turun pada solusi yang berfungsi.
Dengan demikian, ini adalah masalah yang sebenarnya tidak akan saya gunakan
:substitute
sama sekali: ini adalah masalah yang dapat dengan mudah dipecahkan menggunakan perintah mode normal biasa dan makro rekursif:(Jika perlu) Pertama, matikan
'wrapscan'
. Ekspresi reguler yang akan kita gunakan akan cocok dengan teks hasil yang diinginkan serta teks awal, jadi dengan'wrapscan'
on, makro akan terus diputar ulang selamanya. (Atau sampai Anda menyadari apa yang terjadi dan tekan<C-C>
.):Siapkan istilah pencarian Anda (menggunakan basis ekspresi reguler yang sama yang telah disebutkan dalam jawaban yang ada):
(Jika perlu) Melompat kembali ke pertandingan pertama dengan menekan
N
sebanyak yang diperlukan,(Jika perlu) Ubah kecocokan pertama menjadi teks yang diinginkan:
Kosongkan
"q
register dan mulai merekam makro:Tarik penghitung saat ini:
Lompat ke pertandingan berikutnya:
Ganti penghitung saat ini dengan yang baru saja kita tarik:
Tambahkan penghitung:
Mainkan makro
q
. Daftar"q
masih kosong karena kami membersihkannya di langkah 5, jadi tidak ada yang terjadi pada saat ini:Hentikan merekam makro:
Mainkan makro baru, dan tonton!
Seperti halnya semua makro, ini terlihat seperti banyak langkah ketika dijelaskan seperti yang telah saya lakukan di atas, tetapi perhatikan bahwa sebenarnya mengetik ini sangat cepat bagi saya: selain dari rekursif-makro-rekaman-boilerplate mereka semua hanya biasa perintah pengeditan yang saya lakukan sepanjang waktu selama pengeditan. Satu-satunya langkah di mana saya harus melakukan apa pun bahkan mendekati pemikiran adalah langkah 2, di mana saya menulis ekspresi reguler untuk melakukan pencarian.
Diformat sebagai dua perintah mode baris perintah dan serangkaian penekanan tombol, kecepatan jenis solusi ini menjadi lebih jelas: Saya dapat menyulap berikut ini secepat saya bisa mengetiknya 1 :
Saya mungkin bisa menemukan solusi lain pada halaman ini dengan sedikit pemikiran dan beberapa referensi dari dokumentasi 2 , tetapi, setelah Anda memahami bagaimana macro bekerja, mereka benar-benar mudah untuk menghasilkan kecepatan apa pun yang biasanya Anda edit.
1: Ada yang situasi di mana makro memerlukan lebih banyak pemikiran, tapi saya merasa mereka tidak datang banyak dalam praktek. Dan umumnya situasi di mana mereka terjadi adalah situasi di mana makro adalah satu - satunya solusi praktis.
2: Tidak menyiratkan bahwa penjawab lainnya tidak dapat dengan mudah menemukan solusi mereka: mereka hanya membutuhkan keterampilan / pengetahuan yang secara pribadi tidak saya miliki dengan mudah di ujung jari saya. Tetapi semua pengguna Vim tahu cara menggunakan perintah pengeditan reguler!
sumber