Pencarian dan Ganti Multiline

9

Ingin melakukan pencarian dan mengganti file dengan 12000 baris.

Khususnya, jika kejadian ^ SetFontSize 28ada setelah ^Hideblok dan sebelum ^Hideatau sesudahnya ^Show, ubah 28ke 18.

Berikut cuplikan dari file asli.

Hide # Gear - Endgame
    ItemLevel >= 77
    Rarity = Magic
    LinkedSockets >= 3
    BaseType "Runic Hatchet"
    SetTextColor 140 190 255 # Magic Item Highlight
    SetFontSize 28

Hide # Gear - Endgame
    ItemLevel >= 77
    Rarity = Magic
    Sockets >= 3
    BaseType "Runic Hatchet"
    SetTextColor 140 190 255 # Magic Item Highlight
    SetFontSize 28

Show # Gear - Endgame
    ItemLevel >= 83
    Rarity = Normal
    Sockets < 3
    BaseType "Tiger Hook"
    SetTextColor 240 240 240 # Normal Item Highlight
    SetBackgroundColor 70 70 70
    SetFontSize 28

Hasil akhir untuk salah satu Hideblok akan terlihat seperti ini:

Hide # Gear - Endgame
    ItemLevel >= 77
    Rarity = Magic
    LinkedSockets >= 3
    BaseType "Runic Hatchet"
    SetTextColor 140 190 255 # Magic Item Highlight
    SetFontSize 18

Mengganti SetFontSize 28ke SetFontSize 18, tetapi hanya jika muncul di ^Hideblok.

Regex jahat yang saya coba adalah: :%s/^Hide\(.*\)SetFontSize 28$/Hide\1SetFontSize 18/g

Tetapi diberitahu pola tidak ditemukan. Harap beri tahu saya jika ada informasi tambahan yang diperlukan atau jika permintaan saya tidak jelas.

Orang
sumber
5
Apakah setiap Hideblok memiliki SetFontSizegaris (berapapun nilainya)? Jika demikian, Anda dapat menggunakan:%s/Hide\_.\{-\}SetFontSize \zs28/18/
muru
2
@muru whatever be the valueakan menyebabkan masalah, solusi Anda hanya berfungsi jika setiap Hideblok memiliki SetFontSizegaris dan nilainya tepat 28, jika tidak, cocok hingga 28blok lainnya.
dedowsdi

Jawaban:

3

Salah satu cara untuk mengatasi ini adalah dengan menggunakan :globalyang menghasilkan output rentang.

Penggunaan globalperintah biasanya

:[range]g/{pattern}/[cmd]

Ini juga memiliki opsi untuk membuat pola ini menghasilkan rentang daripada pencocokan garis tunggal dengan menggunakan ,dalam bentuk

:[range]g/{first pattern}/,/{second pattern}/[cmd]

Ini menghasilkan rentang yang diterapkan pada perintah.

Misalnya Anda pola pertama akan cocok dengan pertama Hidemasuk dan pola kedua adalah baik Hide, Showatau akhir file (dengan asumsi Anda ingin bahwa Hide kasus terakhir).

:g/Hide/,/\(Hide\|Show\|\%$\)/s/SetFontSize 28/SetFontSize 18/

Regex pertama sederhana /Hide/,. Regex kedua berisi beberapa bagian yang menarik.

  • \(dan \)membuat pengelompokan atom yang cocok
  • \| adalah operasi ATAU
  • \%$ mewakili akhir file

Setelah kami menentukan rentang kami, kami menerapkan pengganti dengan pola dan string seperti biasa.

Harap dicatat bahwa regex yang digunakan dalam contoh ini sangat mendasar. Anda akan ingin memastikan bahwa pengidentifikasi Anda untuk awal dan akhir rentang menangkap area yang tepat.

jecxjo
sumber
3

Sepertinya regex jahat Anda tidak cukup jahat ... :-)

Bagian Pencarian

Pencarian harus diubah menjadi ini:

^Hide\(\(\(Show\|Hide\)\@!\_.\)*\)SetFontSize 28

Ini termasuk beberapa hal yang tidak biasa dan banyak tanda kurung ... Mari kita lihat apa yang kita miliki di sana:

The Caret ( ^)

Tanda sisipan digunakan untuk berarti awal dari garis. Saya pikir kita sudah akrab dengan yang ini.

Poin penting, ^tidak berfungsi kecuali sebagai karakter pertama dalam pola Anda. Setelah itu diambil kata demi kata. Untuk memasukkan awal baris dalam ekspresi Anda, Anda perlu menggunakan \_^. Namun, dalam situasi kami, kami tidak membutuhkan itu.

(Ada fenomena serupa dengan $dan \_$)

Tanda kurung pertama dan terakhir ( \( ... \))

Tanda kurung pertama dan terakhir digunakan sendiri yang artinya akan mengambil apa pun yang muncul di dalamnya dan mengaturnya dalam parameter \1. Anda sudah menggunakannya di regex Anda sendiri, jadi saya akan menganggap Anda juga terbiasa dengan yang ini.

Set kurung kedua

Seperti yang Anda perhatikan, ada tanda kurung kedua yang diikuti oleh tanda bintang \( ... \)*. Ini berarti kami mencari apa pun yang cocok dengan beberapa kali. Ini adalah cara biasa menggunakan tanda bintang sehingga Anda harus terbiasa dengannya.

Set kurung ketiga, OR, dan \_.

Ya, sebenarnya ada tiga tanda kurung sebelum kata Show. Set terakhir ini diperlukan karena dua alasan: \|dan berikut ini @!.

Sehubungan dengan operasi ATAU, Anda harus sudah terbiasa dengannya.

Show\|Hide    or    Hide\|Show

Urutannya tidak penting di sini. Ini \diperlukan di depan |untuk bekerja di vim.

Tanda kurung di sekitar ungkapan ini memungkinkan kita untuk mengikuti ekspresi dengan sesuatu . Di sini @!.

\(Show\|Hide\)@!

Yang ini kurang familiar. Artinya kalau tidak cocok . Penggunaan ini tidak mudah, tetapi Anda harus mengikuti ungkapan itu dengan apa yang ingin Anda ekstrak yang tidak cocok dengan ungkapan tersebut. Inilah mengapa kita memiliki di \_.balik pola itu.

The \_.berarti cocok sesuatu apapun. Berlawanan dengan .karakternya sendiri, yang tidak cocok dengan \nkarakternya. Dengan kata lain, kami mencocokkan karakter apa pun pada sejumlah baris kecuali jika cocok Showatau Hide.

Perhatikan bahwa tanda kurung di sekitar ungkapan itu juga penting seperti tanda bintang, jadi semua ini yang membuatnya bekerja:

\(\(Show\|Hide\)@!\_.\)*

alias mencocokkan berapa pun sampai ke yang berikutnya Showatau Hidekarakter (catatan bahwa hal itu juga akan cocok Showing, Shower, HideMe, dll Anda harus dapat menggunakan \<dan \>jika perlu untuk mencocokkan kata dengan tepat.)

Catatan Samping: untuk mencari di banyak baris, juga dimungkinkan untuk menggunakan \nkarakter dalam pola. Namun, itu tidak serbaguna daripada \_.polanya.

SetFontSize 28

Sekarang bagian ini juga harus disertakan SetFontSize 28. Sama seperti yang Anda miliki di regex Anda. Jika tidak ada yang SetFontSize 28muncul di bagian itu, coba cari lagi di bagian selanjutnya.

Karena negasi di atas (kecocokan kecuali Showatau Hide) pencarian tidak bocor ke bagian berikutnya, mengambil risiko mengacaukannya.

Bagian Penggantian

Penggantinya sama seperti yang Anda miliki:

.../Hide\1SetFontSize 18/

Kami menggunakan tanda kurung dalam Pencarian sehingga \1berfungsi seperti yang diharapkan.

Cari dan Ganti Lengkap

Pola yang dihasilkan seperti ini:

:%s/^Hide\(\(\(Show\|Hide\)@!\_.\)*\)SetFontSize 28/Hide\1SetFontSize 18/

The \(Show\|Hide\)harus mencakup semua kemungkinan header .

Sumber

Regex untuk mencocokkan karakter apa pun termasuk baris baru ( \_.\{-})

Cari baris yang tidak mengandung pola dan pencarian bermanfaat lainnya ( @!)

Dokumentasi Vim: pattern ( \_^)

Alexis Wilke
sumber
1
Saya suka ()*, versi saya jawaban Anda: %s/\v^Hide.*\n(\s+.*\n)*\s*SetFontSize\s+\zs28/16.
dedowsdi