Trova e sostituisci usando le espressioni regolari


26

Ho un file con un sacco di impostazioni predefinite dell'utente. Voglio cambiare parte del testo, ma sto facendo fatica a trovare un matcher e un sostituto. Utilizzando il seguente esempio:

###############################################################################
# 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

Vorrei sostituirlo # Trackpad: ...conrunning "Trackpad: ..."

Risolvendo il problema, ho pensato a qualcosa usando un tester regex:

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

Se provo ad usare questo in Vim non funziona per me:

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

Immagino che il mio problema si riduca a due domande specifiche:

  1. Come posso evitare la ricerca di \npersonaggi e invece assicurarmi #che non compaia alla fine del gruppo di ricerca?
  2. Come posso utilizzare efficacemente i gruppi di acquisizione?

Di seguito sono riportate alcune ottime risposte. Difficile scegliere tra tutti e tre, tuttavia ritengo che la risposta scelta sia la più accurata per le mie specifiche originali. Ti consiglio di provare tutte e tre le risposte con il file effettivo per vedere come ti senti su di esse.

Risposte:


18

Giusto per essere chiari ... credo che tu abbia chiesto che questo fosse il risultato della sostituzione?

###############################################################################
# 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

In tal caso, raccomando il seguente comando:

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

Spiegazione del modello

:s/PATTERN/REPLACEMENT/è il comando sostitutivo . L'accesso percentuale :%slo fa funzionare sull'intero file, anziché solo sulla riga corrente.

Il \n\ndice che la linea di interesse deve verificarsi dopo una riga vuota. Se non ti importasse della precedente riga vuota, ^sarebbe sufficiente.

#\s\+corrisponde a un carattere hash seguito da uno o più caratteri spazi bianchi. \(.*\)cattura tutto il testo successivo sulla linea.

Spiegazione del testo di sostituzione

^M^Minserisce due estremità delle linee per sostituire \n\nquelle presenti nel modello. Altrimenti, il testo verrebbe spostato alla fine della riga che precede la riga vuota. Per digitare ciascuno ^M, premere Ctrl-V Ctrl-M.

Quindi, inserisci la stringa running, seguita da tutto ciò che è stato catturato tra parentesi tra virgolette.


Non riesco a modificare la tua risposta, ma credo che tu intendessi :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/(aggiunta la bandiera "magica"). È davvero difficile scegliere una risposta corretta per la mia domanda originale, ma ritengo che questa sia la più vicina alla mia risposta originale prevista. È anche l'unico che funziona su tutto il file senza la necessità di selezionare un intervallo.
squarefrog,

1
IIRC è possibile utilizzare \rinvece di ^Mottenere nuove linee?
muru,

11

Vorrei usare qualcosa del tipo:

:s/^#\s\+\(.\{-}\):/running "\1":/
  • ^#per abbinare il #carattere ancorato all'inizio della riga (risponde alla domanda 1)
  • \s\+ per abbinare qualsiasi spazio bianco una o più volte
  • \( per iniziare un gruppo (questo risponde alla domanda 2)
  • .\{-}\abbinare qualsiasi personaggio 0 o più volte in modo non avido ; questo è diverso dal fatto .*che cerca di abbinare il meno possibile e non il più possibile. Prova ad aggiungere un :personaggio nel commento per capire perché è importante
  • \) per terminare il sottogruppo.
  • : corrisponde a un letterale :

Sostituiamo quindi questo con il testo desiderato e utilizziamo \1per fare riferimento al gruppo che abbiamo acquisito.

Ho trovato qualcosa usando un tester regex

La sintassi delle espressioni regolari è un po 'come la sintassi wiki: ce ne sono un sacco, sembrano tutte uguali a colpo d'occhio, nessuna di esse è ovviamente migliore di qualsiasi altra, ma ci sono molte differenze.

Oggi, le cosiddette espressioni regolari "compatibili con Perl" sono di fatto predefinite nella maggior parte delle lingue, ma le espressioni regolari di Vim non sono compatibili con le espressioni compatibili con Perl! La sintassi di regexp di Vim risale almeno agli anni '70, quando Perl non era nemmeno in giro.

Puoi vederlo con i sottogruppi, dove devi usare \(e non ((questo è compatibile con la sintassi 'base' POSIX, ma non con la sintassi 'estesa' POSIX più comune o sintassi Perl). Puoi controllarlo aggiungendo il \vflag in un modello (vedi :help /\vper i dettagli), questo lo renderà "più compatibile", ma non completamente (devi ancora usare .{-}per le partite non avide per esempio)

Quindi questo potrebbe spiegare perché l'uso di "un tester regex" funziona quasi, ma non del tutto.

http://www.vimregex.com/ come una buona panoramica / cheatsheet di Vim regexps.


1
Ottima risposta, soprattutto con il motivo per cui regex! = Regex. Per quanto riguarda la tua ricerca e sostituzione, è un po 'complicato in quanto il commento può o meno avere un :. Vedi il file completo per i dettagli github.com/squarefrog/dotfiles/blob/master/osx/…
squarefrog

8

Puoi:

  • cerca le righe che non finiscono in #::/[^#]$/
  • sostituire #\s(.*)all'inizio della riga:s/\v^#\s(.*)/running "\1"/

Per utilizzare i gruppi, è necessario:

  • sfuggire alle parentesi in modo che diventino parte della sintassi regex:, \(.*\)o
  • usa "magia" iniziando l'espressione con \v:s/\v...

Combinandolo:

:/[^#]$/s/\v^#\s(.*)/running "\1"/

1
Funziona alla grande, grazie per aver incluso una spiegazione del significato dei tag piuttosto che solo il testo di cui avevo bisogno per scrivere.
squarefrog,

Grazie per aver chiarito che le parentesi devono essere sfuggite per diventare parte della sintassi regex. Ho sempre avuto un problema con i gruppi regex nel farli funzionare.
Adama,
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.