Ricerca multilinea e sostituzione


9

Vorrebbe eseguire una ricerca e sostituirlo in un file con 12000 righe.

In particolare, se ^ SetFontSize 28esiste un'occorrenza dopo un ^Hideblocco e prima del successivo ^Hideo ^Show, passare 28a 18.

Ecco uno snippet dal file originale.

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

Il risultato finale per uno dei Hideblocchi dovrebbe essere simile al seguente:

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

Sostituzione SetFontSize 28a SetFontSize 18, ma solo se appare in un ^Hideblocco.

La cattiva regex che ho provato è stata: :%s/^Hide\(.*\)SetFontSize 28$/Hide\1SetFontSize 18/g

Ma è stato detto modello non trovato. Per favore fatemi sapere se sono necessarie ulteriori informazioni o se la mia richiesta non è chiara.


5
Ogni Hideblocco ha una SetFontSizelinea (qualunque sia il valore)? In tal caso, potresti usare:%s/Hide\_.\{-\}SetFontSize \zs28/18/
muru,

2
@muru whatever be the valuepotrebbe causare problemi, la tua soluzione funziona solo se ogni Hideblocco ha una SetFontSizelinea e il suo valore è esattamente 28, altrimenti corrisponde fino a 28un altro blocco.
dedowsdi

Risposte:


3

Un modo per risolverlo sarebbe usare :globalquello che genera un output di intervallo.

L'uso tipico del globalcomando sarebbe

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

Ha anche la possibilità di fare in modo che questo modello generi un intervallo piuttosto che una singola riga usando ,nella forma di

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

Questo genera un intervallo che viene applicato al comando.

Per il vostro esempio, il primo modello sarebbe abbinando il primo Hideingresso e il secondo modello è o Hide, Show, o alla fine del file (supponendo che si desidera che lo scorso Nascondi caso).

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

La prima regex è semplice, /Hide/. La seconda regex contiene alcune parti interessanti.

  • \(e \)crea un raggruppamento di atomi da abbinare
  • \| è l'operazione OR
  • \%$ rappresenta la fine del file

Una volta definiti i nostri intervalli, applichiamo il sostituto con uno schema e una stringa come faresti normalmente.

Si noti che il regex utilizzato in questo esempio è molto semplice. Ti consigliamo di assicurarti che i tuoi identificatori per l'inizio e la fine dell'intervallo catturino le aree giuste.


3

Sembra che la tua brutta espressione regolare non era abbastanza brutto ... :-)

Cerca nella sezione

La ricerca dovrebbe essere modificata in questo:

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

Questo include alcune cose insolite e così tante parentesi ... Vediamo cosa abbiamo dentro:

The Caret ( ^)

Il cursore viene utilizzato per indicare l'inizio della riga. Penso che abbiamo già familiarità con questo.

Un punto importante, il ^non funziona se non come il primo personaggio nel tuo schema. Dopo di che è preso alla lettera. Per includere un inizio di riga nella tua espressione devi usare \_^. Tuttavia, nella nostra situazione non ne avevamo bisogno.

(C'è un fenomeno simile con $e \_$)

La prima e l'ultima parentesi ( \( ... \))

La prima e l'ultima parentesi vengono utilizzate da sole, il che significa che afferrerà tutto ciò che appare all'interno e lo imposterà nel parametro \1. L'hai già usato nel tuo regex, quindi suppongo che anche tu abbia familiarità con questo.

La seconda serie di parentesi

Come puoi notare, c'è una seconda serie di parentesi seguita da un asterisco \( ... \)*. Ciò significa che stiamo cercando ciò che corrisponde un numero qualsiasi di volte. Questo è il solito modo di usare l'asterisco, quindi dovresti conoscerlo.

La terza serie di parentesi, OR e \_.

Sì, ci sono in realtà tre parentesi prima della parola Show. Quest'ultimo set è necessario per due motivi: il \|e il seguente @!.

Per quanto riguarda l'operazione OR, dovresti già conoscerla.

Show\|Hide    or    Hide\|Show

L'ordine non ha importanza qui. Il \è necessaria di fronte al |al lavoro in vim.

La parentesi attorno a questa espressione ci consente di seguire l'espressione con qualcosa . Qui il @!.

\(Show\|Hide\)@!

Questo è molto meno familiare. Significa se non abbinato . L'uso di questo non è molto semplice, tuttavia, ma è necessario seguire quell'espressione con ciò che si desidera estrarre che non deve corrispondere a tale espressione. Questo è il motivo per cui abbiamo \_.dietro quel modello.

I \_.mezzi corrispondono a qualsiasi cosa. Contrariamente al .solo, che non corrisponde al \npersonaggio. In altre parole, abbiniamo qualsiasi carattere su qualsiasi numero di linee a meno che non corrisponda Showo Hide.

Nota che anche la parentesi attorno a quell'espressione è importante come l'asterisco, quindi tutta questa cosa è davvero ciò che la fa funzionare:

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

aka importo da fino a quello successivo Showo Hidecaratteri (nota che sarebbe anche corrispondere Showing, Shower, HideMe, ecc Si dovrebbe essere in grado di utilizzare \<e \>, se è necessario abbinare la parola esattamente.)

Nota a margine: per cercare su più righe, è anche possibile utilizzare il \ncarattere nel modello. Tuttavia, non è versatile come il \_.modello.

SetFontSize 28

Ora anche la sezione deve includere SetFontSize 28. Proprio come avevi nella tua regex. Se non SetFontSize 28appare in quella sezione, riprovare a cercare nella sezione successiva.

A causa della negazione sopra (la corrispondenza tranne Showo Hide) la ricerca non passa alla sezione successiva, correndo il rischio di rovinarla.

Sezione di sostituzione

Il sostituto è lo stesso di quello che avevi:

.../Hide\1SetFontSize 18/

Usiamo la parentesi nella ricerca in modo che \1funzioni come previsto.

Ricerca completa e sostituzione

I modelli risultanti sono i seguenti:

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

L' \(Show\|Hide\)dovrebbe includere tutti i possibili intestazioni .

fonti

Regex per abbinare qualsiasi personaggio incluso newline ( \_.\{-})

Cerca linee che non contengono pattern e altre ricerche utili ( @!)

Documentazione Vim: pattern ( \_^)


1
Mi piace la ()*mia versione della vostra risposta: %s/\v^Hide.*\n(\s+.*\n)*\s*SetFontSize\s+\zs28/16.
dedowsdi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.