Vim: s ersetzen die ersten N <g Vorkommen in einer Zeile

13

In vim habe ich manchmal Gelegenheit, die ersten paar Vorkommen eines Matches in einer Zeile zu ersetzen, aber nicht jeder gmöchte. z.B:

a a a a a

zu

b b b a a

Ich weiß, dass ich es gebrauchen könnte :s/a/b/[enter]:[up][enter]:[up][enter], aber das ist bei drei Wiederholungen langweilig genug. Ich habe Zeilen mit möglicherweise mehr als 10 Substitutionen.
Ich habe es versucht:

  • :s/a/b/3g: vim beschwerte sich über nachgestellte Zeichen.
  • :s/a/b/3: Ändert das erste Vorkommen in dieser und den folgenden beiden Zeilen.
  • 3:s/a/b: das gleiche wie vorher.
  • :s/a/b/g3: Ändert alle Vorkommen in dieser und den nächsten beiden Zeilen.
  • :3s/a/b: Ändert das erste Vorkommen in Zeile 3.
  • :/a/,3/a/s/a/b: Ändert das erste Vorkommen in jeder Zeile zwischen der nächsten aund der dritten Zeile ain der Datei (Aufforderung zum Umkehren, falls erforderlich).
  • :/a/,/\([^a]*a\)\{3\}/s/a/b/: Ändert das erste Vorkommen in jeder Zeile zwischen dieser und der nächsten mit 3 a Sekunden (und dies wäre für eine Suche mit mehreren Zeichen nicht einfach erweiterbar gewesen).

Und verschiedene andere Adressierungsmuster, von denen keines funktionierte. Ich muss sagen, ich habe ziemlich viel über das gelernt:s Befehl , eine Antwort auf dieses Problem zu finden, aber ich habe es immer noch nicht gelöst.

Weiß jemand, wie man das macht?

(Bonuspunkte für einen bestimmten Bereich, z. B. zweites bis viertes Vorkommen)

Kevin
quelle
2
Ich bin mir ziemlich sicher, dass Sie das nicht in vim tun können, aber um es weniger langweilig zu machen, kennen Sie "n" und "." im visuellen Modus? Das heißt, Sie verwenden / pattern /, um das zu ändernde Objekt zu finden, ändern es mit "cw" oder was auch immer, und verwenden dann "n" (nur n, keine Anführungszeichen), um das nächste Muster zu finden und "." (nur Punkt, keine Anführungszeichen), um die letzte Bearbeitung durchzuführen.
Bruce Ediger
@BruceEdiger Ich wusste davon nund .obwohl ich nicht daran gedacht habe, sie hier zu verwenden. Sicher eine Verbesserung, danke.
Kevin
s/a/=something/sollte den Trick machen ( :help sub-replace-=). Ich spreche Vim nicht fließend genug, um sofort zu schreiben something.
Gilles 'SO - hör auf böse zu sein'
Hinweis: :[up][enter]Kann durch ersetzt werden &, was immer noch nicht ideal ist, aber zumindest weniger schmerzhaft ist.
Kowh

Antworten:

10

Aufbauend auf der :s/pattern/replacement/gc Idee von Samus_ (dies scheint der einfachste Weg zu sein, um eine korrekte Operation sicherzustellen, wenn das Muster in der Ersetzungszeichenfolge enthalten ist), um das 2. bis 4. Vorkommen in einer einzelnen Zeile zu ersetzen:

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

feedkeys()ist eine Funktion, die die Eingabezeichenfolge in die Tastatureingabewarteschlange einfügt. Der Punkt ist, das Zählen im Voraus durchzuführen, damit Sie sich keine Sorgen machen müssen, dass Sie die Zählung verlieren oder unterbrochen werden.

Für einen allgemeineren Fall, um die Vorkommen Mth bis Nth in einer einzelnen Zeile für N zu ersetzen, das größer oder gleich einem sehr großen M ist :

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

Ersetzen Sie M und N durch die gewünschten Werte (Sie können sogar vimdie triviale mentale Arithmetik ausführen lassen, wenn Sie dies nicht selbst tun möchten). Beachten Sie, dass .dies der String-Verkettungsoperator von VimL ist. Offensichtlich ist dies spart nur Tastenanschläge für großen M . Wenn Sie diese Funktion häufig verwenden, sparen Sie möglicherweise Zeit, um die oben genannten Funktionen in einen benutzerdefinierten Befehl oder eine benutzerdefinierte Funktion einzufügen, da die Eingabe ziemlich umfangreich ist.

jw013
quelle
Hmm. Ich mag diesen. Ich sollte auch eine Funktion dafür schreiben können.
Kevin
8

Für die erste Frage würde ich tun:

:s/a/b
&&

Das zweite ist schwieriger, ich weiß nicht, wie ich es automatisch machen kann, aber Sie können vim dazu bringen, Sie bei jedem Spiel wie folgt aufzufordern:

:s/a/b/gc

Dann antworten Sie auf die ersten n Übereinstimmungen mit "Nein" und auf die anderen mit "Ja".

Samus_
quelle
Hmm, ich habe vergessen c, das könnte die bisher beste vorgeschlagene Lösung sein. Ich müsste immer noch zählen, aber ich denke, es ist die erste Option, die mit Ersetzungen funktioniert, die die Suchzeichenfolge enthalten.
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
quelle
1
Das ist gut, aber es leidet immer noch unter dem Problem, auf das Gilles hingewiesen hat (in einem anderen Beitrag, der seitdem gelöscht worden zu sein scheint), dass es nur funktioniert, wenn der Ersatz das Muster nicht enthält. Obwohl mir die Scripting-Idee gefällt.
Kevin
Eine Sache der Schönheit!
Bischof
1

Ich denke, das könnte funktionieren, zuerst ersetzen, dann 2 Mal wiederholen:

:s/a/b/
2@:
ddsun
quelle