Verwenden Sie das Muster des globalen ex-Befehls in einer Zeile, um ihn in einer anderen Zeile zu ersetzen

8

In meinem fortran-Code habe ich viele Blöcke wie die folgenden

subroutine name(arg1,arg2,arg3,...)
:
end subroutine

und ich möchte, dass sie werden

subroutine name(arg1,arg2,arg3,...)
:
end subroutine name

Wo jeder dieser Blöcke durch eine beliebige Anzahl von Leerzeichen eingerückt werden kann (tatsächlich können solche Blöcke verschachtelt sein). Ich habe es mit dem Befehl versucht

:g/^ *subroutine \(.*\)/;/end subrout/s/end subroutine/& \1

Das ändert jede Zeile (ich habe es in der untersten Zeile gelesen) und ändert nichts, so wie der Puffer \1leer ist. Der Befehl

:g/^ *subroutine \(.*\)/;/end subrout/s/end subroutine/& hello

funktioniert gut, ist aber offensichtlich nicht das, was ich will. Die Frage ist also: Wie kann ich in der Ersatzzeichenfolge ein Muster verwenden, das mit dem globalen ex-Befehl übereinstimmt :g?

BEARBEITEN Ich bearbeite die Frage, da ich zum Zeitpunkt meiner Veröffentlichung die Antwort, die eine Antwort auf den konkreten Fall war, auf den ich mich bezog, eilig akzeptierte, aber nicht auf den Titel der Frage, der etwas allgemeiner ist.

Ich gehe auf den Punkt. Ich habe eine Datei wie die folgende (unsinnig, nur um sie so allgemein wie möglich zu gestalten):

# sec1
fun1  are you a function?
fun2 no.
fun3 ok, nice to meet you!

# 2nd part
first line
third line
ops (it was the second)
there were 3 lines in the preceding #

# fourth group
now there's just one
and foreveeer

(Tatsächlich sind die Zeilen, die jeder Zeile folgen, #Hunderte.)

Ich muss in jeder Zeile nach jeder Zeile #(und vor der folgenden Zeile) Ersetzungen vornehmen #. Diese Ersetzungen sollten alle den Text nach der führenden #Zeile (oder einem Teil davon) verwenden. Ein Beispiel für einen Wunsch, den ich erreichen möchte, ist

# sec1
fun1 in sec1  are you a function?
fun2 in sec1 no.
fun3 in sec1 ok, nice to meet you!

# 2nd part
first in 2nd line
third in 2nd line
ops in 2nd (it was the second)
there in 2nd were 3 lines in the preceding #

# fourth group
now in fourth there's just one
and in fourth foreveeer

Beachten Sie, dass #in den folgenden Zeilen nur das erste folgende Wort eingefügt wird.

Wie ich bereits sagte, möchte ich wissen, ob das Muster des :gBefehls als Ersatzzeichenfolge verwendet werden kann. Ich bin so an dieser Antwort interessiert, da es sehr ärgerlich ist, ein Makro zu registrieren (ein falscher Tastendruck bedeutet, von vorne zu beginnen!), Während ein Befehl wie dieser

:g/^# \(\<\w\+\>\)/+;/^#/- s/\(\<\w\+\>\)\(.\+$\)/\2 \1 \3

es wäre perfekt! ... und es fällt mir schwer zu glauben, dass es keine Möglichkeit gibt, einen Befehl zu verwenden, der die Arbeit erledigt!

Enrico Maria De Angelis
quelle

Antworten:

4

Sie können eine Kombination aus :global, matchit und :normal!:

:g/^\s*subroutine/norm ^whye^%$p

Erläuterung:

  • :g/^\s*subroutine: Für alle übereinstimmenden Zeilen ^\s*subroutinetun Sie:
  • normal: Normalmodus aufrufen (! bedeutet keine ZuordnungenSie nicht verwenden norm!, da die !den Anruf zu matchit entfernt (dank @SatoKatsura))
  • ^Gehen Sie zum ersten nicht leeren Zeichen (nicht 0, um verschachtelte Unterprogramme zu behandeln).
  • whye: gehe zum zweiten Wort (Name), gehe 1 Zeichen (Leerzeichen) zurück und kopiere es (das Leerzeichen soll das Einfügen am Ende etwas erleichtern)
  • ^%: Gehen Sie zurück zum ersten nicht leeren Zeichen und verwenden Sie matchit, um die Übereinstimmung zu finden end
  • $p: nameam Ende der Zeile einfügen (mit einem führenden Leerzeichen)
Marth
quelle
2
norm!tötet %aus matchit. Lösung : :%g/^\s*subroutine/norm ^whye^%$p.
Sato Katsura
Ah du hast recht. Ich habe es tatsächlich getestet, aber ich habe es normstattdessen verwendet norm!, da ich ziemlich sicher war, dass hier keine benutzerdefinierten Einstellungen störten… Guter Fang, und danke für die Korrektur.
Marth
3
@SatoKatsura: Ich verstehe nicht, warum Sie verwenden müssen :%g. Ich habe beide an einem Puffer mit unterschiedlichen und verschachtelten Unterroutinen (und mit -u NONE) ausprobiert und in beiden Fällen die gleichen Ergebnisse erzielt. Ich dachte :global, der Standardbereich war 1,$(dh %). In welchem ​​Fall würde das %einen Unterschied machen?
Marth
5

Eine mögliche Problemumgehung ist die Verwendung eines Makros:

qa/^subroutine<CR>f<space>/end subroutine<CR>$pq

Was so detailliert werden kann:

qa                  Record a macro in the a register
/^subroutine<CR>    Go to the next occurence of a subroutine declaration
f<space>            Go to the space separating "subroutine" and the name
y$                  Yank till the end of line (i.e. the name)
/end subroutine<CR> Go to the next occurence of "end subroutine"
$p                  Put the name at the end of the line
q                   Stop recording the macro

Sie können dann Ihr Makro mit der Anzahl der Unterprogramme ausführen, mit X@adenen Xfortgefahren werden soll

statox
quelle
1
Nun, ich benutze viele Makros (Register c zum Kommentieren, u zum Kommentieren, t zum Tabulator usw.), sodass ein weiteres Makro kein Problem darstellen würde. Mein Standpunkt ist jedenfalls, dass ich das Makro fälschlicherweise mit etwas Unverständlichem überschreiben könnte, ohne es zu merken (q ist in der Nähe von w und ich bin noch kein Meister im Tippen von Berührungen). Also werde ich vorerst auf andere Antworten hoffen / warten.
Enrico Maria De Angelis
2
Fortran kann verschachtelte Unterprogramme haben.
Sato Katsura
4

Hier ist die Makrolösung von @statox , die für Subroutinenparameter und verschachtelte Subroutinen geändert wurde. Dies setzt voraus, dass Sie auch matchit installiert haben :

  • qaq - Register löschen @a
  • qa - Aufnahme im Register starten @a
  • /^\s*subroutine\zs<CR>- suchen nach subroutine; \zsLässt den Cursor auf dem darauf folgenden Feld
  • y2w- den Namen ziehen; 2weil wir den Raum einschließen wollen, wweil wir ein wollen word(dies hört bei (usw. auf)
  • h - Geh nach links bis zum Ende subroutine
  • %- gehe zum Matching end subroutine(drei Beifall für matchit)
  • $p - Fügen Sie den Namen ein
  • _ - gehe zum ersten nicht leeren Zeichen, dh zum Anfang von (the) end
  • % - zurück zum Matching subroutine
  • j- runter, um mehr zu suchen subroutines
  • 0- Gehen Sie zum Zeilenanfang, damit Sie subroutinein der aktuellen Zeile kein verpassen
  • @a - Rufen Sie das aktuelle Makro rekursiv auf
  • q - Makro beenden

Um es auszuführen:

  • :set nowrapscan - Vermeiden Sie eine Endlosschleife: Das Makro wird gerettet, wenn es das Ende der Datei erreicht
  • 1G - Zum Anfang der Datei gehen
  • @a - Makro ausführen
Sato Katsura
quelle
3

Sie können mit einem Ersatzbefehl gehen:

:%s/\v(^subroutine (.+)\_.{-}end subroutine)/\1 \2

Dies stimmt mit dem Ganzen subroutine / end subroutinein Gruppe 1 und dem Unterprogrammnamen in Gruppe 2 überein und verkettet sie.

Das {-}ist nicht gierig, *daher hört es beim ersten gefundenen Element auf.

\_.alles zusammenpassen und a new-line.

nobe4
quelle
2
Dies wird nicht funktionieren, Fortran kann verschachtelte Unterprogramme haben.
Sato Katsura
1
Ich weiß, aber OP hat nichts darüber angegeben. Sein Vorschlag und die andere Antwort funktionieren nicht mit verschachtelten Unterprogrammen. Die Übereinstimmung mit dem Unterprogramm "Schließen" ist insgesamt eine andere Frage.
nobe4
2
Es ist keine große Sache, matchitkann verschachtelte Unterprogramme verarbeiten.
Sato Katsura