Hitta och ersätt med reguljära uttryck

Jag har en fil med en massa användarinställningar. Jag vill ändra en del av texten, men jag kämpar komma med en matcher och ersättare. Med följande exempel:

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

Jag skulle vilja ersätta # Trackpad: ... med running "Trackpad: ..."

För att bryta ner problemet kom jag på något med en regex-testare:

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

Om jag försöker använda detta i Vim fungerar det inte för mig:

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

Jag antar att mitt problem beror på två specifika frågor:

  1. Hur kan jag undvika att söka efter \n tecken och istället se till att # inte visas i slutet av sökgruppen?
  2. Hur kan jag effektivt använda fångstgrupper?

Det finns några bra svar nedan. Svårt att välja mellan alla tre, men jag tycker att det valda svaret är det mest exakta för min ursprungliga specifikation. Jag rekommenderar att du testar alla tre svaren med faktiska filen för att se hur du tycker om dem.

Svar

Bara för att vara tydlig … Jag tror att du bad om att detta skulle vara resultatet av bytet?

############################################################################### # 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 rekommenderar jag följande kommando:

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

Förklaring till mönstret

:s/PATTERN/REPLACEMENT/ är kommandot . Procenttecknet i :%s får det att fungera på hela filen snarare än bara den aktuella raden.

\n\n säger att raden av intresse måste ske efter en tom rad. Om du inte brydde dig om föregående tomma rad skulle ^ vara tillräckligt.

#\s\+ matchar en hash tecken följt av ett eller flera mellanslagstecken. \(.*\) fångar all efterföljande text på raden.

Förklaring till ersättningstexten

^M^M infogar två ändar av rader för att ersätta \n\n som fanns i mönstret. Annars flyttas texten till slutet av raden före den tomma raden. För att skriva varje ^M, tryck på Ctrl-V Ctrl-M .

Sätt sedan in strängen running, följt av vad som fångades inom parentes inom dubbla citat.

Kommentarer

  • Jag kan inte redigera ditt svar men jag tror att du menade :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/ (lade till ” magi ” flagga). Det är verkligen svårt att välja ett korrekt svar på min ursprungliga fråga, men jag tycker att det här svaret ligger närmast mitt ursprungliga förväntade svar. Det är också den enda som fungerar genom hela filen utan att behöva välja ett intervall.
  • IIRC kan du använda \r istället för ^M för att få nya rader?

Svar

Jag skulle använda något som:

:s/^#\s\+\(.\{-}\):/running "\1":/ 
  • ^# för att matcha # karaktär förankrad i början av raden (detta svarar på fråga 1)
  • \s\+ för att matcha valfritt utrymme en eller flera gånger
  • \( för att starta en grupp (det här svarar på fråga 2)
  • .\{-}\ för att matcha alla tecken 0 eller flera gånger i en icke-girig väg ; detta skiljer sig från .* genom att det försöker matcha så lite som möjligt och inte så mycket som möjligt. Försök lägga till ett : -tecken i kommentaren för att se varför detta betyder
  • \) för att avsluta undergruppen.
  • : matchar en bokstavlig :

Vi ersätter sedan detta med texten du vill, och använd \1 för att hänvisa till gruppen vi fångade.

Jag kom på något med en regex-testare

Syntax för reguljärt uttryck är lite som wiki-syntax: det finns en massa dem, de ser alla ut som en överblick, ingen av dem är uppenbarligen bättre än någon annan, men det finns många skillnader.

Idag är de så kallade ”Perl-kompatibla” reguljära uttrycken de facto standard på de flesta språk, men Vim-reguljära uttryck är inte kompatibel med Perl-kompatibla uttryck! Vim regexp-syntax går tillbaka till åtminstone ”70”, när Perl inte ens var runt.

Du kan se detta med undergrupperna, där du måste använda \( och inte ( (detta är kompatibelt med POSIX ”grundläggande” syntax, men inte med den vanligaste POSIX ”utökade” syntaxen eller Perl-syntaxen).Du kan kontrollera detta genom att lägga till \v -flaggan i ett mönster (Se :help /\v för detaljer) kommer detta att göra det ”mer kompatibelt”, men inte helt (du måste fortfarande använda .{-} för till exempel icke-giriga matcher)

Så detta kan förklara varför användning av ”en regex-testare” nästan, men inte riktigt, fungerar.

http://www.vimregex.com/ som en bra översikt / cheatsheet av Vim regexps.

Kommentarer

Svar

Du kan:

  • söka efter rader som inte slutar i #: :/[^#]$/
  • ersätt #\s(.*) i början av raden: s/\v^#\s(.*)/running "\1"/

För att använda grupper måste du antingen:

  • undvika parenteserna så att de blir en del av regex-syntaxen: \(.*\), eller
  • använd ”magi” av börjar uttrycket med \v: s/\v...

Kombinera det:

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

Kommentarer

  • Detta fungerar fantastiskt, tack för att du har förklarat vad taggarna betyder snarare än bara texten jag behövde skriv.
  • Tack för att du klargjorde att parenteserna har t o undvikas för att bli en del av regex-syntaxen. Jag har alltid haft problem med regex-grupper att få dem att fungera.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *