Znajdź i zamień, używając wyrażeń regularnych

26

Mam plik z wieloma domyślnymi ustawieniami użytkownika. Chcę zmienić część tekstu, ale staram się wymyślić moduł dopasowujący i zamiennik. Korzystając z następującego przykładu:

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

Chciałbym zamienić # Trackpad: ...zrunning "Trackpad: ..."

Rozwiązując problem, wymyśliłem coś za pomocą testera wyrażeń regularnych:

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

Jeśli spróbuję użyć tego w Vimie, to nie działa dla mnie:

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

Chyba mój problem sprowadza się do dwóch konkretnych pytań:

  1. Jak mogę uniknąć wyszukiwania \nznaków, a zamiast tego upewnić się, #że nie pojawia się na końcu grupy wyszukiwania?
  2. Jak mogę skutecznie korzystać z grup przechwytywania?

Poniżej znajduje się kilka świetnych odpowiedzi. Trudno wybrać między wszystkimi trzema, jednak uważam, że wybrana odpowiedź jest najdokładniejsza dla mojej oryginalnej specyfikacji. Zalecam wypróbowanie wszystkich trzech odpowiedzi z rzeczywistym plikiem, aby zobaczyć, co o nich myślisz.

żaba kwadratowa
źródło

Odpowiedzi:

18

Żeby było jasne… Sądzę, że poprosiłeś o to, aby było to wynikiem zmiany?

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

W takim przypadku polecam następujące polecenie:

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

Objaśnienie wzoru

:s/PATTERN/REPLACEMENT/jest poleceniem zastępczym . Logowanie procentowe :%spowoduje, że działa on na całym pliku, a nie tylko na bieżącym wierszu.

\n\nMówi, że linia zainteresowania muszą wystąpić po pustym wierszu. Jeśli nie przejmujesz się poprzednią pustą linią, ^wystarczy.

#\s\+dopasowuje znak krzyżyka, po którym następuje co najmniej jeden biały znak. \(.*\)przechwytuje cały kolejny tekst w wierszu.

Objaśnienie tekstu zastępczego

^M^Mwstawia dwa końce linii, aby zastąpić te, \n\nktóre były obecne we wzorze. W przeciwnym razie tekst zostałby przeniesiony na koniec linii poprzedzającej pustą linię. Aby wpisać każdy ^M, naciśnij Ctrl-V Ctrl-M.

Następnie wstaw ciąg running, a następnie wszystko, co zostało przechwycone w nawiasach w cudzysłowach.

200_sukces
źródło
Nie mogę edytować twojej odpowiedzi, ale myślę, że miałeś na myśli :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/(dodał flagę „magia”). Naprawdę trudno jest wybrać prawidłową odpowiedź na moje pierwotne pytanie, ale czuję, że ta odpowiedź jest najbliższa mojej pierwotnej oczekiwanej odpowiedzi. Jest to również jedyny, który działa w całym pliku bez potrzeby wybierania zakresu.
squarefrog
1
IIRC, którego możesz użyć \rzamiast ^Muzyskać nowe linie?
mur 30.04.2015
11

Użyłbym czegoś takiego:

:s/^#\s\+\(.\{-}\):/running "\1":/
  • ^#dopasować #znak zakotwiczony na początku linii (odpowiada to pytanie 1)
  • \s\+ aby dopasować dowolne białe znaki jeden lub więcej razy
  • \( założyć grupę (odpowiada to pytanie 2)
  • .\{-}\dopasowywać dowolny znak 0 lub więcej razy w sposób nie chciwy ; różni się .*to tym, że stara się dopasować tak mało, jak to możliwe, a nie tak bardzo, jak to możliwe. Spróbuj dodać :znak w komentarzu, aby zobaczyć, dlaczego to ma znaczenie
  • \) aby zakończyć podgrupę.
  • : pasuje dosłownie :

Następnie zamieniamy go na żądany tekst i używamy \1w odniesieniu do przechwyconej grupy.

Wymyśliłem coś za pomocą testera wyrażeń regularnych

Składnia wyrażeń regularnych przypomina trochę składnię wiki: jest ich kilka, wszystkie wyglądają podobnie na pierwszy rzut oka, żadna z nich nie jest oczywiście lepsza niż jakakolwiek inna, ale istnieje wiele różnic.

Dzisiaj tak zwane wyrażenia regularne „kompatybilne z Perlem” są de facto domyślnymi ustawieniami w większości języków, ale wyrażenia regularne Vima nie są kompatybilne z wyrażeniami kompatybilnymi z Perlem! Składnia wyrażeń regularnych Vima sięga co najmniej lat 70-tych, kiedy Perla nawet nie było w pobliżu.

Możesz to zobaczyć w podgrupach, których musisz użyć, \(a nie ((jest to zgodne ze „podstawową” składnią POSIX, ale nie z bardziej powszechną składnią „rozszerzoną” POSIX lub składnią Perl). Możesz to kontrolować, dodając \vflagę do wzorca (zobacz :help /\vszczegóły), dzięki temu będzie „bardziej kompatybilny”, ale nie do końca (musisz na przykład używać .{-}do niepochodnych dopasowań)

To może wyjaśniać, dlaczego używanie „testera wyrażeń regularnych” działa prawie, ale nie całkiem.

http://www.vimregex.com/ jako dobry przegląd / ściągawka Vim regexps.

Martin Tournoij
źródło
1
Świetna odpowiedź, zwłaszcza z tym, dlaczego regex! = Regex. Jeśli chodzi o wyszukiwanie i zamianę, jest to trochę trudne, ponieważ komentarz może zawierać lub nie :. Zobacz pełną plik po szczegóły github.com/squarefrog/dotfiles/blob/master/osx/...
squarefrog
8

Możesz:

  • wyszukaj linie, które nie kończą się na #::/[^#]$/
  • zamień #\s(.*)na początku wiersza:s/\v^#\s(.*)/running "\1"/

Aby korzystać z grup, musisz:

  • uciec od nawiasów, aby stały się częścią składni wyrażenia regularnego: \(.*\)lub
  • użyj „magii” , rozpoczynając wyrażenie od \v:s/\v...

Łącząc to:

:/[^#]$/s/\v^#\s(.*)/running "\1"/
muru
źródło
1
Działa to doskonale, dzięki za wyjaśnienie, co oznaczają tagi, a nie tylko tekst, który musiałem napisać.
squarefrog
Dziękujemy za wyjaśnienie, że nawiasy klamrowe muszą być poprzedzone znakami ucieczki, aby stać się częścią składni wyrażeń regularnych. Zawsze miałem problem z grupami wyrażeń regularnych w zmuszaniu ich do pracy.
Adama,