Jeg har en fil med en rekke brukerstandarder i. Jeg vil endre noe av teksten, men jeg sliter kommer med en matcher og erstatning. Ved å bruke følgende eksempel:
############################################################################### # 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
Jeg vil erstatte # Trackpad: ...
med running "Trackpad: ..."
Når jeg brøt opp problemet, kom jeg på noe ved hjelp av en regex-tester:
/\n\n#\s(.*)/g
Hvis jeg prøver å bruke dette i Vim, fungerer det ikke for meg:
:/\n\n#\s(.*)/running "\1"/g
Jeg antar at problemet mitt koker ned til to spesifikke spørsmål:
- Hvordan kan jeg unngå å søke etter
\n
tegn, og i stedet sørge for at#
ikke vises på slutten av søkegruppen? - Hvordan kan jeg effektivt bruke fangstgrupper?
Det er noen gode svar nedenfor. Vanskelig å velge mellom alle tre, men jeg føler at det valgte svaret er det mest nøyaktige for min originale spesifikasjon. Jeg anbefaler at du prøver alle de tre svarene med faktiske filen for å se hvordan du har det.
Svar
Bare for å være tydelig … Jeg tror du ba om at dette skulle være resultatet av erstatningen?
############################################################################### # 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
I så fall anbefaler jeg følgende kommando:
:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/
Forklaring på mønsteret
:s/PATTERN/REPLACEMENT/
er erstatning -kommandoen. Prosenttegnet i :%s
får det til å fungere på hele filen, i stedet for bare den nåværende linjen.
\n\n
sier at interessefeltet må oppstå etter en tom linje. Hvis du ikke brydde deg om den forrige tomme linjen, ville ^
være tilstrekkelig.
#\s\+
samsvarer med en hash tegn etterfulgt av ett eller flere mellomromstegn. \(.*\)
fanger all påfølgende tekst på linjen.
Forklaring på erstatningsteksten
^M^M
setter inn to ender av linjer for å erstatte \n\n
som var til stede i mønsteret. Ellers flyttes teksten til slutten av linjen foran den tomme linjen. For å skrive hver ^M
, trykk Ctrl-V Ctrl-M .
Deretter setter du inn strengen running
, etterfulgt av det som ble fanget i parentes innenfor dobbelt anførselstegn.
Kommentarer
Svar
Jeg vil bruke noe sånt som:
:s/^#\s\+\(.\{-}\):/running "\1":/
-
^#
for å matche#
tegnet forankret i begynnelsen av linjen (dette svarer på spørsmål 1) -
\s\+
for å matche hvilket som helst hvitt mellomrom en eller flere ganger -
\(
for å starte en gruppe (dette svarer på spørsmål 2) -
.\{-}\
for å matche et hvilket som helst tegn 0 eller flere ganger i en ikke-grådig måte ; dette er forskjellig fra.*
ved at den prøver å matche så lite som mulig, og ikke så mye som mulig. Prøv å legge til et:
tegn i kommentaren for å se hvorfor dette betyr noe -
\)
for å avslutte undergruppen. -
:
samsvarer med en bokstavelig:
Vi erstatter dette med teksten du vil, og bruk \1
for å referere til gruppen vi fanget.
Jeg fant på noe ved hjelp av en regex-tester
Syntaks for vanlig uttrykk er litt som wiki-syntaks: det er en haug med dem, de ser alle like ut med et øyeblikk, ingen av dem er åpenbart bedre enn noe annet, men det er mange forskjeller.
I dag er de såkalte «Perl-kompatible» regulære uttrykkene de facto standard på de fleste språk, men Vim-regulære uttrykk er ikke kompatibel med Perl-kompatible uttrykk! Vim regexp syntaks går tilbake til minst «70», da Perl ikke var engang rundt.
Du kan se dette med undergruppene, der du må bruke \(
og ikke (
(dette er kompatibelt med POSIX «grunnleggende» syntaks, men ikke med den vanligste POSIX «utvidede» syntaksen eller Perl-syntaksen).Du kan kontrollere dette ved å legge til \v
flagget i et mønster (Se :help /\v
for detaljer), vil dette gjøre det «mer kompatibelt», men ikke helt (du må fortsatt bruke .{-}
for ikke-grådige kamper for eksempel)
Så dette kan forklare hvorfor bruk av «en regex-tester» nesten, men ikke helt, fungerer.
http://www.vimregex.com/ som en god oversikt / cheatsheet av Vim regexps.
Kommentarer
- Flott svar, spesielt med hvorfor regex! = regex. Når det gjelder søket og erstattet, er det ‘ litt vanskelig, da kommentaren kanskje ikke har
:
. Se hele filen for detaljer github.com/squarefrog/dotfiles/blob/master/osx/…
Svar
Du kan:
- søke etter linjer som ikke slutter i
#
::/[^#]$/
- erstatt
#\s(.*)
i begynnelsen av linjen:s/\v^#\s(.*)/running "\1"/
For å bruke grupper, må du enten:
- unnslippe parentesene slik at de blir en del av regex-syntaksen:
\(.*\)
, eller - bruk «magi» av begynner uttrykket med
\v
:s/\v...
Kombinere det:
:/[^#]$/s/\v^#\s(.*)/running "\1"/
Kommentarer
- Dette fungerer glimrende, takk for at du inkluderer en forklaring på hva kodene betyr i stedet for bare teksten jeg trengte skriv.
- Takk for at du tydeliggjorde at parentesene har t o bli rømt for å bli en del av regex-syntaksen. Jeg hadde alltid et problem med regex-grupper for å få dem til å jobbe.
:%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/
(la til » magi » flagg). Det er veldig vanskelig å velge et riktig svar på det opprinnelige spørsmålet mitt, men jeg føler at dette svaret er nærmest mitt opprinnelige forventede svar. Det er også den eneste som fungerer gjennom hele filen uten behov for å velge et område.\r
i stedet for^M
for å få nye linjer?