Ho un file con un sacco di impostazioni predefinite dellutente. Vorrei modificare parte del testo, ma ho difficoltà inventando 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 “sostituire # Trackpad: ...
con running "Trackpad: ..."
Rompendo il problema, ho escogitato qualcosa utilizzando un tester regex:
/\n\n#\s(.*)/g
Se provo a usarlo in Vim non funziona per me:
:/\n\n#\s(.*)/running "\1"/g
Immagino che il mio problema si riduca a due domande specifiche:
- Come posso evitare di cercare
\n
caratteri e assicurarmi invece che#
non venga visualizzato alla fine del gruppo di ricerca? - Come posso utilizzare efficacemente i gruppi di cattura?
Di seguito sono riportate alcune ottime risposte. Difficile scegliere tra tutti e tre, tuttavia ritengo che la risposta scelta sia la più accurata per la mia specifica originale. Ti consiglio di provare tutte e tre le risposte con il file effettivo per vedere cosa ne pensi.
Risposta
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, consiglio il seguente comando:
:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/
Spiegazione del pattern
:s/PATTERN/REPLACEMENT/
è il comando substitute . Il segno di percentuale :%s
lo fa funzionare sullintero file, anziché solo sulla riga corrente.
Il \n\n
dice che la riga di interesse deve essere posta dopo una riga vuota. Se non ti interessa la riga vuota precedente, allora ^
sarebbe sufficiente.
#\s\+
corrisponde a un hash carattere seguito da uno o più caratteri di spazio. \(.*\)
acquisisce tutto il testo successivo sulla riga.
Spiegazione del testo sostitutivo
^M^M
inserisce due estremità di riga per sostituire \n\n
che erano presenti nel pattern. In caso contrario, il testo verrebbe spostato alla fine della riga prima della riga vuota. Per digitare ogni ^M
, premi Ctrl-V Ctrl-M .
Quindi, inserisci la stringa running
, seguita da tutto ciò che è stato catturato tra parentesi tra virgolette.
Commenti
Risposta
Vorrei usare qualcosa come:
:s/^#\s\+\(.\{-}\):/running "\1":/
-
^#
in modo che corrisponda al carattere#
ancorato allinizio della riga (questo risponde alla domanda 1) -
\s\+
per trovare uno o più spazi vuoti -
\(
per avviare un gruppo (questo risponde alla domanda 2) -
.\{-}\
per trovare qualsiasi carattere 0 o più volte in un modo non avido ; questo è diverso da.*
in quanto cerca di corrispondere il meno possibile e non il più possibile. Prova ad aggiungere un:
carattere nel commento per capire perché è importante -
\)
per terminare il sottogruppo. -
:
corrisponde a un:
Quindi lo sostituiamo con il testo vuoi e usa \1
per fare riferimento al gruppo che abbiamo catturato.
Mi è venuto in mente qualcosa utilizzando un tester di regex
La sintassi delle espressioni regolari è un po come la sintassi wiki: ce ne sono un sacco, si assomigliano tutti a colpo docchio, nessuno di loro è ovviamente migliore di qualsiasi altra, ma ci sono molte differenze.
Oggi, le cosiddette espressioni regolari “compatibili con Perl” sono di fatto limpostazione predefinita nella maggior parte delle lingue, ma le espressioni regolari di Vim non lo sono compatibile con espressioni compatibili con Perl! La sintassi regexp di Vim risale almeno agli “70”, quando Perl non era nemmeno in giro.
Puoi vederlo con i sottogruppi, dove devi usare \(
e non (
(questo è compatibile con la sintassi POSIX “base”, ma non con la più comune sintassi POSIX “estesa” o sintassi Perl).Puoi controllarlo aggiungendo il flag \v
in un pattern (vedi :help /\v
per i dettagli), questo lo renderà “più compatibile”, ma non completamente (devi comunque usare .{-}
per le corrispondenze non avide, ad esempio)
Quindi questo potrebbe spiegare perché usare “un tester regex” quasi, ma non del tutto, funziona.
http://www.vimregex.com/ come una buona panoramica / cheatsheet delle espressioni regolari di Vim.
Commenti
- Ottima risposta, specialmente con why regex! = regex. Per quanto riguarda la ricerca e la sostituzione, ‘ è un po complicato in quanto il commento potrebbe o meno avere un
:
. Vedi il file completo per i dettagli github.com/squarefrog/dotfiles/blob/master/osx/…
Risposta
Puoi:
- cercare righe che non finiscono in
#
::/[^#]$/
- sostituisci
#\s(.*)
allinizio di la riga:s/\v^#\s(.*)/running "\1"/
Per utilizzare i gruppi, devi:
- sfuggire alle parentesi in modo che diventano parte della sintassi regex:
\(.*\)
o - usa “magic” di che inizia lespressione con
\v
:s/\v...
Combinandola:
:/[^#]$/s/\v^#\s(.*)/running "\1"/
Commenti
- Funziona brillantemente, grazie per aver incluso una spiegazione del significato dei tag anziché solo il testo di cui avevo bisogno scrivi.
- Grazie per aver chiarito che le parentesi hanno t o essere sottoposto a escape per entrare a far parte della sintassi regex. Ho sempre avuto un problema con i gruppi di espressioni regolari nel farli funzionare.
:%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/
(aggiunta la ” magia ” flag). È davvero difficile da scegliere una risposta corretta per la mia domanda originale, ma ritengo che questa risposta sia la più vicina alla mia risposta originale prevista. È anche lunico che funziona su tutto il file senza bisogno di selezionare un intervallo.\r
invece di^M
per ottenere nuove righe?