Ich möchte jedes Vorkommen eines bestimmten Musters suchen und durch eine Dezimalzahl ersetzen, die bei 1
jeder Übereinstimmung beginnt und um eins erhöht wird.
Ich kann ähnlich formulierte Fragen finden, bei denen es nicht darum geht, einen Zähler zu erhöhen, sondern jede Übereinstimmung um einen festen Betrag zu ändern. Andere ähnliche Fragen betreffen das Einfügen von Zeilennummern anstelle eines inkrementierenden Zählers.
Beispiel vor:
#1
#1.25
#1.5
#2
Nach:
#1
#2
#3
#4
Meine realen Daten enthalten viel mehr Text rund um das Material, das ich neu nummerieren möchte.
substitute
Hippietrail
quelle
quelle
perldo
, können Sie verwenden:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Antworten:
Sie müssen durch einen Staat ersetzt werden. Ich erinnere mich, dass ich eine (/ mehrere?) Komplette Lösung für diese Art von Problemen auf SO bereitgestellt habe .
Hier ist eine andere Möglichkeit, um fortzufahren (1). Jetzt gehe ich in zwei Schritten vor:
Welches gibt:
Wenn Sie es nicht gewohnt sind, reguläre Ausdrücke zu vimieren, verwende ich
:h /\zs
und gebe\ze
an, mit welchem Untermuster ich übereinstimme. Dann stimme ich mit einer Reihe von Ziffern überein, möglicherweise gefolgt von einem Punkt und anderen Ziffern. Dies ist nicht perfekt für eine Gleitkommazahl, aber dies reicht hier aus.Hinweis: Für eine einfache Benutzeroberfläche müssen Sie es in ein paar Funktionen + Befehl zusammenfassen. Wieder gibt es Beispiele für SO / vim ( hier , hier , hier ). Heutzutage weiß ich genug über vim, um diesen Trick nicht in einen Befehl zu packen. In der Tat kann ich diesen Befehl beim ersten Versuch schreiben, während ich mir einige Minuten Zeit nehme, um mir den Namen des Befehls zu merken.
(1) Ziel ist es, einen Zustand zwischen den Substitutionen aufrechtzuerhalten und das aktuelle Vorkommen durch etwas zu ersetzen, das vom aktuellen Zustand abhängt.
Dank können
:s\=
wir etwas einfügen, das aus einer Berechnung resultiert.Bleibt das Problem des Staates. Entweder definieren wir eine Funktion, die einen externen Status verwaltet, oder wir aktualisieren uns selbst einen externen Status. In C (und verwandten Sprachen) hätten wir so etwas wie
length++
oder verwenden könnenlength+=1
. Leider kann in vim-Skripten+=
nicht sofort verwendet werden. Es muss entweder mit:set
oder mit verwendet werden:let
. Dies bedeutet, dass:let length+=1
eine Zahl erhöht wird, aber nichts zurückgegeben wird. Wir können nicht schreiben:s/pattern/\=(length+=1)
. Wir brauchen noch etwas.Wir brauchen mutierende Funktionen. dh Funktionen, die ihre Eingaben mutieren. Wir haben
setreg()
,map()
,add()
und wahrscheinlich mehr. Beginnen wir mit ihnen.setreg()
mutiert ein Register. Perfekt. Wir könnensetreg('a',@a+1)
wie in der Lösung von @Doktor OSwaldo schreiben . Und doch ist das nicht genug.setreg()
ist eher eine Prozedur als eine Funktion (für diejenigen unter uns, die Pascal, Ada ... kennen). Dies bedeutet, dass nichts zurückgegeben wird. Eigentlich gibt es etwas zurück. Nominal Exit (dh nicht außergewöhnliche Exits) geben immer etwas zurück. Wenn wir vergessen haben, etwas zurückzugeben, wird standardmäßig 0 zurückgegeben - dies gilt auch für integrierte Funktionen. Deshalb ist in seiner Lösung der Ersatzausdruck tatsächlich\=@a+setreg(...)
. Tricky, nicht wahr?map()
könnte auch verwendet werden. Wenn wir von einer Liste mit einer einzelnen 0 (:let single_length=[0]
) ausgehen, können wir sie dank erhöhenmap(single_length, 'v:val + 1')
. Dann müssen wir die neue Länge zurückgeben. Im Gegensatz dazusetreg()
wirdmap()
die mutierte Eingabe zurückgegeben. Das ist perfekt, die Länge wird an der ersten (und eindeutigen und damit auch letzten) Position der Liste gespeichert. Der Ersatzausdruck könnte sein\=map(...)[0]
.add()
ist die, die ich oft aus Gewohnheit benutze (ich habe gerade darübermap()
nachgedacht, und ich habe ihre jeweiligen Auftritte noch nicht festgelegt). Die Idee dabeiadd()
ist, eine Liste als aktuellen Status zu verwenden und am Ende vor jeder Ersetzung etwas anzuhängen. Ich speichere den neuen Wert oft am Ende der Liste und verwende ihn als Ersatz. Daadd()
auch die mutierte Eingabeliste zurückgegeben wird, können wir verwenden :\=add(state, Func(state[-1], submatch(0)))[-1]
. Im Fall von OP müssen wir uns nur daran erinnern, wie viele Übereinstimmungen bisher erkannt wurden. Es reicht aus, die Länge dieser Statusliste zurückzugeben. Daher mein\=len(add(state, whatever))
.quelle
\=
dass ein Ausdruck erwartet wird und dass im Gegensatz zu Ci+=1
kein Ausdruck inkrementiert und zurückgegeben wird. Dies bedeutet, dass\=
ich etwas brauche, das einen Zähler ändern kann und einen Ausdruck zurückgibt (der diesem Zähler entspricht). Bisher habe ich nur die Manipulationsfunktionen für Listen (und Wörterbücher) gefunden. @Doktor OSwaldo hat eine andere Mutationsfunktion verwendet (setreg()
). Der Unterschied besteht darin, dasssetreg()
niemals etwas zurückgegeben wird, was bedeutet, dass immer die Nummer zurückgegeben wird0
.Aber Vorsicht, es wird Ihr Register überschreiben
a
. Ich denke, es ist ein bisschen einfacher als Lucs Antwort, aber vielleicht ist seine schneller. Wenn diese Lösung irgendwie schlechter ist als seine, würde ich gerne Feedback hören, warum seine Antwort besser ist. Jedes Feedback zur Verbesserung der Antwort wird sehr geschätzt!(Es basiert auch auf einer SO-Antwort von mir /programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim -edi / 43539546 # 43539546 )
quelle
@a+setreg('a',@a+1)
kürzer ist alslen(add(t,1))
. Ansonsten ist das ein schöner anderer schmutziger Trick :). Ich habe nicht an diesen gedacht. In Bezug auf die Verwendung einer Wörterbuch-Mutationsfunktion im Ersatztext von:s
und habesubstitute()
ich festgestellt, dass dies viel schneller ist als explizite Schleifen - daher die Implementierung meiner Listenfunktionen in lh-vim-lib . Ich denke, Ihre Lösung wird meiner ebenbürtig sein, vielleicht etwas schneller, ich weiß es nicht.@a
unverändert. In Skripten ist dies IMO wichtig. Im interaktiven Modus weiß ich als Endbenutzer, welches Register ich verwenden kann. Das Spielen mit einem Register ist weniger wichtig. In meiner Lösung wird im interaktiven Modus eine globale Variable durcheinander gebracht. In einem Skript wäre es eine lokale Variable.+3
könnte ich so etwas schreiben\=add(thelist, 3 + get(thelist, -1, 0))[-1]
.Ich habe eine ähnliche, aber andere Frage gefunden, die ich vor ein paar Jahren gestellt habe, und es geschafft, eine ihrer Antworten zu ändern, ohne vollständig zu verstehen, was ich tat, und es hat großartig funktioniert:
Insbesondere verstehe ich nicht, warum meine nicht verwendet wird
%
oder warum ich nur eine einfache Variable verwende, die die anderen Antworten aus irgendeinem Grund vermeiden.quelle
s//g
Anweisung nicht aktualisiert wird . Auf jeden Fall ist es eine interessante Lösung. Vielleicht kann @LucHermitte Ihnen mehr über Vor- und Nachteile erzählen, da mein Wissen über Vimscript im Vergleich zu seinem ziemlich begrenzt ist.printf()
jedoch -, als Listen in Vim 7 eingeführt wurden. Aber ich muss zugeben, ich hätte nicht erwartet (/ erinnere mich nicht?)<bar>
, Dass sie zum Geltungsbereich von gehören:global
- IOW, das Szenario, das ich erwartet hatte, war, das:sub
auf die übereinstimmenden Zeilen anzuwenden und danni
ganz am Ende einmal zu erhöhen. Ich erwarte, dass diese Lösung etwas langsamer ist. Aber ist das wirklich wichtig? Wichtig ist, wie einfach es ist, eine funktionierende Lösung aus Speicher + Versuch & Irrtum zu finden. Zum Beispiel bevorzugen Vimgolfers Makros.g/s//
erlaubt das Scope-Verhalten andere schmutzige Tricks. Ich danke Ihnen beiden für die interessanten Antworten und die Diskussion. Ich lerne nicht oft so viel, wenn ich eine Antwort gebe =).Es gibt bereits drei großartige Antworten auf dieser Seite, aber wie Luc Hermitte in einem Kommentar vorgeschlagen hat , ist es wichtig, wie schnell und einfach Sie auf eine funktionierende Lösung stoßen können, wenn Sie dies direkt tun.
Als solches ist dies ein Problem, das ich eigentlich gar nicht verwenden würde
:substitute
: Es kann leicht mit regulären Normalmodusbefehlen und einem rekursiven Makro gelöst werden:(Falls erforderlich) Schalten Sie zuerst aus
'wrapscan'
. Der reguläre Ausdruck, den wir verwenden werden, stimmt sowohl mit dem gewünschten Ergebnistext als auch mit dem Anfangstext überein. Wenn diese Option aktiviert ist, wird'wrapscan'
das Makro ansonsten für immer wiedergegeben. (Oder bis Sie erkennen, was passiert und drücken<C-C>
.):Richten Sie Ihren Suchbegriff ein (unter Verwendung des gleichen regulären Basisausdrucks, der bereits in den vorhandenen Antworten erwähnt wurde):
(Falls erforderlich) Kehren Sie zum ersten Spiel zurück, indem Sie
N
so oft wie nötig drücken.(Falls erforderlich) Ändern Sie die erste Übereinstimmung in den gewünschten Text:
Löschen Sie das
"q
Register und beginnen Sie mit der Aufnahme eines Makros:Ziehen Sie den aktuellen Zähler:
Zum nächsten Spiel springen:
Ersetzen Sie den aktuellen Zähler durch den, den wir gerade gezogen haben:
Erhöhen Sie den Zähler:
Makro abspielen
q
. Das Register"q
ist noch leer, da wir es in Schritt 5 gelöscht haben. Daher passiert zu diesem Zeitpunkt nichts:Beenden Sie die Aufzeichnung des Makros:
Spielen Sie das neue Makro und schauen Sie zu!
Wie bei allen Makros sieht dies nach vielen Schritten aus, wenn ich sie wie oben beschrieben erläutere. Beachten Sie jedoch, dass das Eintippen dieser Schritte für mich sehr schnell geht: Abgesehen von der rekursiven Makroaufzeichnungs-Boilerplate sind sie alle nur die regulären Bearbeitungsbefehle Ich führe die ganze Zeit während der Bearbeitung aus. Der einzige Schritt, in dem ich etwas tun musste, das sich dem Denken näherte , war Schritt 2, in dem ich den regulären Ausdruck schrieb, um die Suche durchzuführen.
Als zwei Befehle im Befehlszeilenmodus und eine Reihe von Tastenanschlägen formatiert, wird die Geschwindigkeit dieser Art von Lösung klarer: Ich kann Folgendes so schnell heraufbeschwören, wie ich es 1 eingeben kann :
Ich hätte mir wahrscheinlich die anderen Lösungen auf dieser Seite mit ein wenig Nachdenken und einigen Verweisen auf die Dokumentation 2 einfallen lassen können , aber wenn Sie erst einmal verstanden haben, wie Makros funktionieren, sind sie wirklich einfach mit der Geschwindigkeit zu erstellen, die Sie normalerweise bearbeiten.
1: Es gibt Situationen, in denen Makros mehr Nachdenken erfordern, aber ich finde, dass sie in der Praxis nicht viel auftauchen. Und im Allgemeinen treten sie in Situationen auf, in denen ein Makro die einzig praktikable Lösung ist.
2: Um nicht zu implizieren, dass die anderen Antwortenden ihre Lösungen nicht so einfach hätten finden können: Sie benötigen nur Fähigkeiten / Kenntnisse, die ich persönlich nicht so einfach zur Hand habe. Aber alle Vim-Benutzer wissen, wie man reguläre Bearbeitungsbefehle verwendet!
quelle