Grup pencocokan bersarang di regex

8

Saya memiliki usecase umum ketika saya mengubah beberapa ekspresi python dengan cara berikut:

value 1
value 2
value 3

ke

['value 1', 'value 2', 'value 3']

Cara termudah mungkin dengan menggunakan pemetaan, tetapi saya ingin menggunakan substitusi untuk tugas ini.

Sejauh ini saya mendapat:

s/\(.*\n\)\+/[&]/g

Yang mengakibatkan

[value 1
value 2
value 3
]

Ini menimbulkan pertanyaan, karena saya ingin dapat mencocokkan \(.*\), tetapi tidak \ndan menggunakan hasil yang cocok di dalam a '...'.

Apakah Anda tahu bagaimana melakukan ini?

nobe4
sumber
2
Saya tidak tahu bagaimana melakukannya dalam satu substitusi, tetapi Anda bisa melakukannya dalam 2 saat dalam mode visual (setelah memilih ekspresi python): :'<,'>s/\v(.*)\n/'\1', / | s/\v(.*), /[\1]/Anda bisa mengubah ini menjadi pemetaan visual: xnoremap ,x :s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>dan mungkin menjadi pemetaan normal jika ekspresi ada di dalam paragraf: nnoremap ,x :'{+1,'}-1s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>Di sini pemetaan akan ,x.
user9433424
1
tidak bisa melakukan dengan regex, tetapi menggunakan perintah eksternal:%! echo "[$(sed "s/.*/'&',/" % | tr '\n' ' ' | sed 's/, $//')]"
Sundeep

Jawaban:

5

Edit

Dimungkinkan untuk melakukan ini dalam satu ekspresi jika kita menggunakan "sub-ganti-ekspresi." Lihat bawah untuk info tentang itu.

/ Edit

Masalahnya di sini adalah Anda ingin melakukan dua hal yang berbeda.

  1. Beroperasi pada pertandingan secara keseluruhan (mis. Mengelilinginya dengan [])

  2. Operasikan pada setiap item dalam pertandingan (mis. Mengelilingi dengan '',)

Anda dapat dengan mudah melakukan keduanya:

  1. :s/\(.\+\n\)\+/[&]/
  2. :%s/\(.\+\)\n/'\1', /

tetapi sejauh yang saya tahu tidak ada cara untuk melakukan keduanya dalam satu operasi. Saya memang mencoba untuk mendapatkan output yang tepat dengan sesuatu seperti:

:s/\(\(.\+\)\n\)\+/[\2]/

Tapi tentu saja masalah dengan ini adalah bahwa \2pertandingan hanya pertandingan terakhir dari set kedua kurung memori \(\)dan tidak "mengingat" apa pun sebelumnya. Jadi Anda berakhir hanya dengan baris terakhir.

Saya akan merekomendasikan melakukan beberapa pemrosesan pra / pasca dengan tambahan :s/// perintah untuk menyingkirkan baris baru sebelum / setelah fakta. Inilah yang saya pikirkan

function! FormatExpression()
   .,/\n^$/s/\(.*\)\n/'\1', /
   s/\(.*\), /[\1]/
endfunction

Baris 1 (Hapus baris baru)

  • .,/\n^$/Ini adalah pengubah rentang untuk pencarian dan penggantian. Tanpa ini, perintah akan melanjutkan untuk memutilasi seluruh file Anda. Saat ini ia beralih dari baris saat ini ., ke baris kosong berikutnya\n^$ . Saya tidak yakin bagaimana Anda berniat untuk berpisah, tetapi Anda perlu cara untuk menghentikannya.
  • s/ Awal pencarian dan ganti perintah
  • \(.*\)\n Cocokkan seluruh baris, tetapi hanya simpan bagian tanpa baris baru.
  • '\1', Ganti baris dengan pertandingan yang dikelilingi oleh tanda kutip tunggal dan tambahkan koma.

Baris 2 (Surround in kurung)

  • \(.*\), Cocokkan seluruh baris tetapi bukan koma dan ruang terakhir
  • [\1] Dikelilingi dengan tanda kurung dan juga menghapus koma dan ruang berakhir berlebihan.

Saya akan terus mencari ke dalam ini, tetapi saat ini saya tidak berpikir itu mungkin dengan satu ekspresi. :(

EDIT:

Saya telah menemukan cara untuk melakukan ini dengan satu ekspresi! Internal ini sebenarnya adalah dua pergantian pemain, tetapi adalah teknis satu ekspresi. Inilah yang saya pikirkan:

:s/\v((.+\n)*.+)\n/\= "['" . substitute(submatch(1), '\n', "', '", 'g') . "']" /
  • :s///: Lakukan substitusi
  • \v((.+\n)*.+)\n: Pada dasarnya kumpulkan semua baris non-kosong berikutnya dan simpan semuanya kecuali untuk final \n
  • \=Mengizinkan kami menggunakan ekspresi dalam penggantian (lihat :h sub-replace-expression)
  • substitute(submatch(1)...): Mengganti semua yang tersimpan \ndengan', '
  • "['" . ... . "']": Prepends ['dan append']

Ini akan mulai pada posisi kursor dan pergi sampai menemukan garis kosong ( ^\n). Tidak meraih yang terakhir\n adalah penting karena tanpa bagian itu kita memiliki tambahan ',yang tidak kita inginkan pada akhirnya.

Beberapa orang mungkin menganggap ini lebih kompleks daripada jawaban dua ekspresi sebelumnya. Tetapi saya pikir saya akan melanjutkan dan menambahkan ini karena sebenarnya mungkin untuk melakukannya dengan satu ekspresi. :)

Tumbler41
sumber
2

Sorot secara visual, lalu:

:'<,'> s/.*/['&']/ | *j! | s/]\[/, /ge

Ini mengelilingi setiap baris, untuk membuat misalnya ['value 1'], bergabung dengan mereka semua, lalu menggantikan yang berdekatan ]dan [dengan koma-ruang.

Ngomong -ngomong, dokumentasi untuk *di *j!ada di :help cpo-star. Yang agak sulit ditemukan.

Antony
sumber
Kerja bagus :)
nobe4
Sebenarnya Anda bisa menggunakan :'<,'>s/\v(.*)(\_.)/['\1']/dan menghapus bergabung.
nobe4
Ya, tapi itu memakan final \n, itu sebabnya saya menggunakan :join. Saya mungkin seharusnya menyebutkan itu. :-)
Antony
1
Bagaimana kalau '<,'>s/.*/['&']/ | *s/]\_.\[/, /begitu?
nobe4
1
Ya, itu lebih baik. Meskipun saya mungkin menulis bagian kedua sebagai *s/]\n\[/, /e.
Antony