Vim: s zastępuje pierwsze N ​​<g wystąpienia w linii

13

W vim czasami mam okazję zastąpić kilka pierwszych wystąpień dopasowania na linii, ale nie każdy gchciałby. na przykład:

a a a a a

do

b b b a a

Wiem, że mógłbym użyć :s/a/b/[enter]:[up][enter]:[up][enter], ale to dość nużące przy trzech powtórzeniach, mam linie z potencjalnie 10+ podstawieniami.
Próbowałem:

  • :s/a/b/3g: vim narzekał na końcowe znaki.
  • :s/a/b/3: zmienia pierwsze wystąpienie w tym i kolejnych dwóch wierszach.
  • 3:s/a/b: tak samo jak poprzednio.
  • :s/a/b/g3: zmienia wszystkie wystąpienia tego i następnych dwóch wierszy.
  • :3s/a/b: zmienia pierwsze wystąpienie w linii 3.
  • :/a/,3/a/s/a/b: zmienia pierwsze wystąpienie w każdej linii między kolejną aa trzecią linią zawartą aw pliku (w razie potrzeby monit o cofnięcie).
  • :/a/,/\([^a]*a\)\{3\}/s/a/b/: zmienia pierwsze wystąpienie w każdym wierszu między tym a następnym z 3 as (i nie byłoby to łatwe do rozszerzenia na wyszukiwanie wielu znaków).

I różne inne wzorce adresowania, z których żaden nie działał. Muszę powiedzieć, że sporo się dowiedziałem o :spoleceniu, które próbuje znaleźć odpowiedź na ten problem, ale nadal go nie rozwiązałem.

Czy ktoś wie jak to zrobić?

(punkty bonusowe za określony zasięg, np. od drugiego do czwartego wystąpienia)

Kevin
źródło
2
Jestem prawie pewien, że nie możesz tego zrobić w vimie, ale aby uczynić to mniej nudnym, czy wiesz o „n” i „.” w trybie wizualnym? Oznacza to, że używasz / pattern /, aby znaleźć rzecz do zmiany, zmień ją za pomocą „cw” lub cokolwiek, a następnie użyj „n” (tylko n, bez cudzysłowów), aby znaleźć następny wzór i naciśnij „.” (tylko kropka, bez cudzysłowów), aby wykonać ostatnią edycję.
Bruce Ediger,
@BruceEdiger Wiedziałem o tym ni .chociaż nie pomyślałem, aby ich tutaj użyć. Z pewnością poprawa, dzięki.
Kevin,
s/a/=something/powinien wykonać trick ( :help sub-replace-=). Nie jestem wystarczająco biegły w Vimie, żeby pisać somethingod razu.
Gilles „SO- przestań być zły”,
Uwaga: :[up][enter]można go zastąpić &, co wciąż nie jest idealne, ale przynajmniej jest mniej bolesne.
Kowh,

Odpowiedzi:

10

Opierając się na :s/pattern/replacement/gc pomyśle z Samus_ (który wydaje się być najprostszym sposobem na zapewnienie poprawnego działania, gdy wzorzec jest zawarty w ciągu zastępującym), aby zamienić 2–4 wystąpienie w jednym wierszu:

:call feedkeys("nyyyq") | s/pat/string/gc

feedkeys()to funkcja, która wpycha ciąg wejściowy do kolejki wprowadzania na klawiaturze. Chodzi o to, aby zliczyć z góry, abyś nie musiał się martwić utratą liczenia lub przerwaniem.

W przypadku bardziej ogólnym przypadku, wymienić mc przez N-te zdarzenia w jednej linii dla N większy niż lub równy bardzo dużej M :

:call feedkeys(repeat("n", M-1) . repeat("y", N-M+1) . "q") | s/pat/string/gc

Zamień M i N na żądane wartości (możesz nawet pozwolić vimna trywialną arytmetykę mentalną, jeśli nie chcesz tego zrobić sam). Zauważ, że .jest to operator konkatenacji ciągów VimL. Oczywiście to tylko oszczędza klawiszy dla dużych M . Jeśli często korzystasz z tej funkcji, możesz zaoszczędzić czas na umieszczenie powyższego polecenia w niestandardowej komendzie lub funkcji, ponieważ wpisywanie jest dość trudne.

jw013
źródło
Hmm Ten mi się podoba. Powinienem też być w stanie napisać dla niego funkcję.
Kevin
8

W przypadku pierwszego pytania chciałbym:

:s/a/b
&&

Drugi jest trudniejszy, nie wiem, jak to zrobić automatycznie, ale możesz sprawić, by vim wyświetlał monity przy każdym meczu w następujący sposób:

:s/a/b/gc

Następnie odpowiadasz „nie” na pierwsze n dopasowań, a „tak” na pozostałe.

Samus_
źródło
Hmm, zapomniałem c, że to może być najlepsze zaproponowane rozwiązanie. Wciąż musiałbym liczyć, ale myślę, że to pierwsza opcja, która działałaby z zamiennikami zawierającymi wyszukiwany ciąg.
Kevin,
6
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a

:3,6g/^/let i=0 | while i<3 | s/a/b/ | let i+=1 | endwhile

a a a a a
a a a a a
b b b a a
b b b a a
b b b a a
b b b a a
a a a a a
kev
źródło
1
To dobrze, ale nadal występuje problem, na który zwrócił uwagę Gilles (w innym poście, który wydaje się być usunięty), że działa tylko wtedy, gdy zamiennik nie zawiera wzorca. Chociaż podoba mi się pomysł na skrypt.
Kevin,
Coś pięknego!
biskup
1

Myślę, że to może zadziałać, najpierw wymień, a następnie powtórz 2 razy:

:s/a/b/
2@:
ddsun
źródło