Temukan dan ganti menggunakan ekspresi reguler

26

Saya memiliki file dengan banyak pengguna default. Saya ingin mengubah beberapa teks, tapi saya kesulitan membuat korek api dan mengganti. Menggunakan contoh berikut:

###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories, and input                 #
###############################################################################

# Trackpad: enable tap to click for this user and for the login screen
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true

Saya ingin mengganti # Trackpad: ...denganrunning "Trackpad: ..."

Memecah masalah, saya datang dengan sesuatu menggunakan penguji regex:

/\n\n#\s(.*)/g

Jika saya mencoba dan menggunakan ini di Vim, itu tidak berfungsi untuk saya:

:/\n\n#\s(.*)/running "\1"/g

Saya kira masalah saya bermuara pada dua pertanyaan spesifik:

  1. Bagaimana saya bisa menghindari mencari \nkarakter, dan sebaliknya memastikan #tidak muncul di akhir grup pencarian?
  2. Bagaimana saya bisa secara efektif menggunakan kelompok tangkap?

Ada beberapa jawaban bagus di bawah ini. Sulit untuk memilih di antara ketiganya, namun saya merasa jawaban yang dipilih adalah yang paling akurat untuk spesifikasi asli saya. Saya sarankan Anda mencoba ketiga jawaban dengan file yang sebenarnya untuk melihat bagaimana perasaan Anda tentang mereka.

kodok persegi
sumber

Jawaban:

18

Hanya untuk memperjelas ... Saya yakin Anda meminta ini menjadi hasil substitusi?

###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories, and input                 #
###############################################################################

running "Trackpad: enable tap to click for this user and for the login screen"
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true

Dalam hal ini, saya merekomendasikan perintah berikut:

:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/

Penjelasan polanya

:s/PATTERN/REPLACEMENT/adalah perintah pengganti . Persen masuk :%smembuatnya berfungsi pada seluruh file, bukan hanya baris saat ini.

Yang \n\nmengatakan bahwa garis bunga harus terjadi setelah garis kosong. Jika Anda tidak peduli dengan baris kosong sebelumnya, maka ^sudah cukup.

#\s\+cocok dengan karakter hash diikuti oleh satu atau lebih karakter spasi putih. \(.*\)menangkap semua teks berikutnya di telepon.

Penjelasan teks pengganti

^M^Mmenyisipkan dua ujung garis untuk mengganti \n\nyang ada dalam pola. Jika tidak, teks akan dipindahkan ke akhir baris sebelum baris kosong. Untuk mengetik masing-masing ^M, tekan Ctrl-V Ctrl-M.

Kemudian, masukkan string running, diikuti oleh apa pun yang ditangkap dalam tanda kurung dalam tanda kutip ganda.

200_sukses
sumber
Saya tidak dapat mengedit jawaban Anda, tetapi saya yakin maksud Anda :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/(menambahkan bendera "ajaib"). Sangat sulit untuk memilih jawaban yang benar untuk pertanyaan awal saya, tetapi saya merasa jawaban ini adalah yang paling dekat dengan jawaban asli saya yang diharapkan. Ini juga satu-satunya yang berfungsi di seluruh file tanpa perlu memilih rentang.
squarefrog
1
Anda bisa menggunakan IIRC \rdaripada ^Mmendapatkan baris baru?
muru
11

Saya akan menggunakan sesuatu seperti:

:s/^#\s\+\(.\{-}\):/running "\1":/
  • ^#untuk mencocokkan #karakter berlabuh di awal baris (ini menjawab pertanyaan 1)
  • \s\+ untuk mencocokkan spasi putih satu kali atau lebih
  • \( untuk memulai grup (ini menjawab pertanyaan 2)
  • .\{-}\untuk mencocokkan karakter 0 atau lebih banyak kali dengan cara yang tidak serakah ; ini berbeda dari .*yang mencoba untuk mencocokkan sesedikit mungkin, dan tidak sebanyak mungkin. Coba tambahkan :karakter dalam komentar untuk melihat mengapa ini penting
  • \) untuk mengakhiri subkelompok.
  • : cocok dengan literal :

Kami kemudian mengganti ini dengan teks yang Anda inginkan, dan gunakan \1untuk merujuk ke grup yang kami tangkap.

Saya datang dengan sesuatu menggunakan regex tester

Sintaks ekspresi reguler sedikit mirip dengan sintaksis wiki: ada banyak dari mereka, mereka semua terlihat sama dalam sekejap, tidak ada yang jelas lebih baik daripada yang lain, tetapi ada banyak perbedaan.

Saat ini, ekspresi reguler yang disebut "Perl-kompatibel" adalah default de-facto di sebagian besar bahasa, tetapi ekspresi reguler Vim tidak kompatibel dengan ekspresi yang kompatibel dengan Perl! Sintaks regim Vim kembali ke setidaknya 70-an, ketika Perl bahkan tidak ada.

Anda dapat melihat ini dengan subkelompok, di mana Anda harus menggunakan \(dan tidak ((ini kompatibel dengan sintaksis POSIX 'dasar', tetapi tidak dengan sintaksis POSIX 'extended' atau sintaks Perl yang lebih umum). Anda dapat mengontrol ini dengan menambahkan \vbendera dalam pola (Lihat :help /\vuntuk detail), ini akan membuatnya "lebih kompatibel", tetapi tidak sepenuhnya (Anda masih harus menggunakan .{-}untuk pertandingan yang tidak serakah misalnya)

Jadi ini mungkin menjelaskan mengapa menggunakan "tester regex" hampir, tetapi tidak cukup, berfungsi.

http://www.vimregex.com/ sebagai ikhtisar / cheatsheet yang baik dari Vim regexps.

Martin Tournoij
sumber
1
Jawaban yang bagus, terutama dengan mengapa regex! = Regex. Adapun pencarian Anda dan ganti, agak rumit karena komentar mungkin atau mungkin tidak :. Lihat file lengkap untuk detail github.com/squarefrog/dotfiles/blob/master/osx/…
squarefrog
8

Kamu bisa:

  • cari baris yang tidak berakhir pada #::/[^#]$/
  • ganti #\s(.*)di awal baris:s/\v^#\s(.*)/running "\1"/

Untuk menggunakan grup, Anda harus:

  • keluar dari tanda kurung sehingga menjadi bagian dari sintaks regex:, \(.*\)atau
  • gunakan "magic" dengan memulai ekspresi dengan \v:s/\v...

Menggabungkannya:

:/[^#]$/s/\v^#\s(.*)/running "\1"/
muru
sumber
1
Ini bekerja dengan sangat baik, terima kasih telah menyertakan penjelasan tentang arti tag daripada hanya teks yang perlu saya tulis.
squarefrog
Terima kasih telah menjelaskan bahwa tanda kurung harus dilepaskan untuk menjadi bagian dari sintaks regex. Saya selalu memiliki masalah dengan kelompok regex dalam membuat mereka bekerja.
Adama