Znajdź i zamień za pomocą wyrażeń regularnych

Mam plik z kilkoma domyślnymi ustawieniami użytkownika. Chcę zmienić część tekstu, ale mam problemy wymyślanie dopasowywania i zamiany. 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 

Chcę zastąpić # Trackpad: ... z running "Trackpad: ..."

Rozwiązując problem, wpadłem na coś, używając testera wyrażeń regularnych:

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

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

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

Myślę, że mój problem sprowadza się do dwóch konkretnych pytań:

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

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

Odpowiedź

Dla jasności… Wydaje mi się, że prosiłeś, aby to wynikało z podstawienia?

############################################################################### # 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 zalecam następującą komendę:

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

Wyjaśnienie wzorca

:s/PATTERN/REPLACEMENT/ jest poleceniem substytutem . Znak procentu :%s sprawia, że działa on na całym pliku, a nie tylko na bieżącym wierszu.

\n\n mówi, że interesująca nas linia musi występować po pustym wierszu. Jeśli poprzedni pusty wiersz nie był dla Ciebie ważny, wystarczyłoby ^.

#\s\+ dopasowuje hash znak, po którym następuje jeden lub więcej białych znaków. \(.*\) przechwytuje cały kolejny tekst w wierszu.

Objaśnienie tekstu zastępczego

^M^M wstawia dwa końce wierszy, aby zastąpić \n\n, które były obecne we wzorcu. W przeciwnym razie tekst zostałby przeniesiony na koniec wiersza poprzedzający pusty wiersz. Aby wpisać ^M, naciśnij klawisze Ctrl-V Ctrl-M .

Następnie wstaw ciąg running, a po nim wszystko, co zostało zapisane w nawiasach w podwójnych cudzysłowach.

Komentarze

  • Nie mogę edytować Twojej odpowiedzi, ale myślę, że chodziło Ci o :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/ (dodano ” magiczne ” flaga). To naprawdę trudne do wybrania poprawna odpowiedź na moje pierwotne pytanie, ale czuję, że jest ona najbliższa mojej pierwotnie oczekiwanej odpowiedzi. Jest także jedynym, który działa w całym pliku bez konieczności wybierania zakresu.
  • IIRC możesz użyć \r zamiast ^M, aby uzyskać nowe linie?

Odpowiedź

Chciałbym użyć czegoś takiego:

:s/^#\s\+\(.\{-}\):/running "\1":/ 
  • ^#, aby dopasować # znak zakotwiczony na początku wiersza (odpowiedź na pytanie 1)
  • \s\+, aby dopasować dowolną białą spację raz lub więcej razy
  • \(, aby rozpocząć grupę (to odpowiada na pytanie 2)
  • .\{-}\, aby dopasować dowolny znak 0 lub więcej razy w niechciwy sposób ; różni się to od .* tym, że stara się dopasować jak najmniej, a nie tak bardzo, jak to możliwe. Spróbuj dodać znak : w komentarzu, aby zobaczyć, dlaczego ma to znaczenie.
  • \), aby zakończyć podgrupę.
  • : dopasowuje literał :

Następnie zastępujemy to tekstem chcesz i użyj \1, aby odnieść się do grupy, którą przechwyciliśmy.

Wymyśliłem coś, używając tester wyrażeń regularnych

Składnia wyrażeń regularnych jest trochę podobna do składni wiki: jest ich kilka, na pierwszy rzut oka wszystkie wyglądają podobnie, żadne z nich jest oczywiście lepszy niż jakikolwiek inny, ale jest wiele różnic.

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

Możesz to zobaczyć w podgrupach, w których musisz użyć \( a nie ( (jest to zgodne z „podstawową” składnią POSIX, ale nie z bardziej powszechną „rozszerzoną” składnią POSIX lub składnią Perla).Możesz to kontrolować, dodając we wzorcu flagę \v (patrz :help /\v aby uzyskać szczegółowe informacje), dzięki temu będzie bardziej kompatybilny, ale nie do końca (na przykład nadal musisz używać .{-} dla niechcianych dopasowań)

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

http://www.vimregex.com/ jako dobry przegląd / ściągawka do wyrażeń regularnych Vima.

Komentarze

  • Świetna odpowiedź, zwłaszcza dlaczego regex! = regex. Jeśli chodzi o wyszukiwanie i zamianę, ' jest nieco skomplikowane, ponieważ komentarz może zawierać : lub nie. Zobacz pełny plik, aby uzyskać szczegółowe informacje github.com/squarefrog/dotfiles/blob/master/osx/…

Odpowiedź

Możesz:

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

Aby używać grup, musisz albo:

  • zmienić znaczenie nawiasów, aby stają się częścią składni wyrażenia regularnego: \(.*\) lub
  • użyj „magic” przez rozpoczynając wyrażenie od \v: s/\v...

Łącząc:

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

Komentarze

  • Działa to wspaniale, dziękuję za wyjaśnienie znaczenia tagów, a nie tylko tekst, którego potrzebowałem napisz.
  • Dziękuję za wyjaśnienie, że nawiasy mają t o zostać wyłączone, aby stać się częścią składni wyrażenia regularnego. Zawsze miałem problem z grupami wyrażeń regularnych przy ich uruchamianiu.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *