Ersetzen Sie eine Reihe von Sternchen durch eine nummerierte Liste


16

Stellen Sie sich vor, ich hätte folgenden Text:

some random stuff
* asdf
* foo
* bar
some other random stuff

Ich möchte die Sternchen-Aufzählungszeichen wie folgt durch Zahlen ersetzen:

some random stuff
1. asdf
2. foo
3. bar
some other random stuff

Wie kann das in vim gemacht werden?


Warum gehst du nicht für Plugins? Ähnlich
verhält

Es ist so erstaunlich und cool, dass jeder seine Antworten inkrementiert, aber da Markdown sie für Sie nummeriert, warum nicht einfach alle machen 1.? :%s/^* /1. /Würde es also tun. Das scheint viel weniger Arbeit zu sein.
Küken

Antworten:


14

Sie können den folgenden Befehl versuchen:

:let c=0 | g/^* /let c+=1 | s//\=c.'. '

Zuerst initialisiert es die Variable c( let c=0), dann führt es den globalen Befehl gaus, der nach dem Muster sucht ^*(ein Zeilenanfang, gefolgt von einem Sternchen und einem Leerzeichen).

Immer wenn eine Zeile mit diesem Muster gefunden wird, führt der globale Befehl den Befehl aus:
let c+=1 | s//\=c.'. '
Er erhöht die Variable c( let c+=1) und |ersetzt ( s) das zuvor gesuchte Muster ( //) durch die Auswertung eines Ausdrucks ( \=):
den Inhalt der cverketteten Variablen ( .) mit der Zeichenfolge'. '


Wenn Sie nicht alle Zeilen aus Ihrem Puffer ändern möchten, sondern nur einen bestimmten Absatz, können Sie einen Bereich an den globalen Befehl übergeben. So ändern Sie beispielsweise nur die Zeilen, deren Nummer zwischen 5 und 10 liegt:

:let c=0 | 5,10g/^* /let c+=1 | s//\=c.'. '

Wenn Sie eine Datei mit mehreren ähnlichen Listen haben, die Sie konvertieren möchten, zum Beispiel:

some random stuff                 some random stuff                      
* foo                             1. foo                                 
* bar                             2. bar                                 
* baz                             3. baz                                 
some other random stuff           some other random stuff                
                           ==>                                                
some random stuff                 some random stuff                      
* foo                             1. foo                                 
* bar                             2. bar                                 
* baz                             3. baz                                 
* qux                             4. qux                                 
some other random stuff           some other random stuff                

Sie können dies mit dem folgenden Befehl tun:

:let [c,d]=[0,0] | g/^* /let [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')] | s//\=c.'. '

Es ist nur eine Variante des vorherigen Befehls, der die Variable zurücksetzt, cwenn Sie zu einer anderen Liste wechseln. Um festzustellen, ob Sie sich in einer anderen Liste befinden, wird in der Variablen ddie Nummer der letzten Zeile gespeichert, in der eine Ersetzung vorgenommen wurde.
Der globale Befehl vergleicht die aktuelle Zeilennummer ( line('.')) mit d+1. Wenn sie identisch sind, bedeutet dies, dass wir uns in derselben Liste wie zuvor befinden, und cwird inkrementiert ( c+1). Andernfalls bedeutet dies, dass wir uns in einer anderen Liste befinden und czurückgesetzt ( 1) werden.

Innerhalb einer Funktion let [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')]könnte der Befehl folgendermaßen umgeschrieben werden:

let c = line('.') == d+1 ? c+1 : 1
let d = line('.')

Oder so:

if line('.') == d+1
    let c = c+1
else
    let c = 1
endif
let d = line('.')

Um einige Tastenanschläge zu speichern, können Sie auch den benutzerdefinierten Befehl definieren :NumberedLists, der einen Bereich akzeptiert, dessen Standardwert 1,$( -range=%) ist:

command! -range=% NumberedLists let [c,d]=[0,0] | <line1>,<line2>g/^* /let [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')] | s//\=c.'. '

Wann :NumberedListswird ausgeführt <line1>und <line2>wird automatisch durch den von Ihnen verwendeten Bereich ersetzt.

Um alle Listen im Puffer zu konvertieren, geben Sie Folgendes ein: :NumberedLists

Nur die Listen zwischen Zeile 10 und 20: :10,20NumberedLists

Nur die visuelle Auswahl: :'<,'>NumberedLists


Weitere Informationen finden Sie unter:

:help :range
:help :global
:help :substitute
:help sub-replace-expression
:help list-identity    (section list unpack)
:help expr1
:help :command

9

Dies funktioniert nur mit einer neueren Vim-Version (die hat :h v_g_CTRL-A):

  1. Block-wählen Sie die Aufzählungszeichen ( *) und ersetzen Sie sie mit 0(Cursor auf erste ist *): Ctrl-v j j r 0.
  2. Vorherigen Block erneut auswählen und mit Zähler inkrementieren :gv g Ctrl-a

... und das ist es :)


(Wenn Sie einen Punkt nach jeder Nummer haben wollen, ändern 1. Schritt: Ctrl-v j j s 0 . Esc)


9

Wählen Sie die Zeilen visuell aus und führen Sie den folgenden Ersetzungsbefehl aus:

:'<,'>s/*/\=line('.') - line("'<") + 1 . '.'

Siehe :help sub-replace-expression, :help line()und :help '<.

Um die Zeilen nicht auswählen zu müssen, können Rückwärts- und Vorwärtssuchen mit Offsets verwendet werden, um den Substitutionsbereich wie folgt festzulegen:

:?^[^*]?+1,/^[^*]/-1s/*/\=line('.') - search('^[^[:digit:]]', 'bn') . '.'

Sehen :help cmdline-ranges


2

Ein anderer Weg:

:let n = 1 | g/^* /s//\=printf('%d. ', n)/g | let n = n + 1

0

Sie können auch benutzerdefinierte Operatoren definieren

Sie können sie den Tastenfolgen '*und zuordnen '#. Die Markierungen *und #sind nicht vorhanden, sodass Sie keine Standardfunktionalität überschreiben. Der Grund für die Wahl 'als Präfix ist, eine Art Mnemonik zu erhalten. Sie fügen ein Zeichen vor einigen Zeilen ein. Und normalerweise verwenden Sie das Präfix, um zu einer Marke zu gelangen '.

fu! s:op_list_bullet(...) abort range

    if a:0
        let [lnum1, lnum2] = [line("'["), line("']")]
    else
        let [lnum1, lnum2] = [line("'<"), line("'>")]
    endif

    if !empty(matchstr(getline(lnum1), '^\s*\d\s*\.'))
        let pattern     = '\d\s*\.\s\?'
        let replacement = '* '

    elseif count(['-', '*'], matchstr(getline(lnum1), '\S'))
        let pattern     = '\v\S\s*'
        let replacement = ''

    else
        let pattern     = '\v\ze\S'
        let replacement = '* '
    endif

    let cmd = 'keepj keepp %s,%s s/%s/%s'

    sil exe printf(cmd, lnum1, lnum2, pattern, replacement)
endfu

fu! s:op_list_digit(...) abort range
    let l:c = 0

    if a:0
        let [lnum1, lnum2] = [line("'["), line("']")]
    else
        let [lnum1, lnum2] = [a:firstline, a:lastline]
    endif

    if count(['-', '*'], matchstr(getline(lnum1), '\S'))
        let pattern     = '\S\s*'
        let replacement = '\=l:c.". "'

    elseif !empty(matchstr(getline(lnum1), '^\s*\d\s*\.'))
        let pattern     = '\d\s*\.\s\?'
        let replacement = ''

    else
        let pattern     = '\v^\s*\zs\ze\S'
        let replacement = '\=l:c.". "'
    endif

    let cmd = 'keepj keepp %s,%s g/%s/let l:c = line(".") == line("'']")+1 ?
                                                \ l:c+1 : 1 |
                                                \ keepj keepp s/%s/%s'

    sil exe printf(cmd, lnum1, lnum2, pattern, pattern, replacement)
endfu

nno <silent> '*     :<C-U>set opfunc=<SID>op_list_bullet<CR>g@
nno <silent> '**    :<C-U>set opfunc=<SID>op_list_bullet
                    \<Bar>exe 'norm! ' . v:count1 . 'g@_'<CR>
xno <silent> '*     :call <SID>op_list_bullet()<CR>

nno <silent> '#     :<C-U>set opfunc=<SID>op_list_digit<CR>g@
nno <silent> '##    :<C-U>set opfunc=<SID>op_list_digit
                    \<Bar>exe 'norm! ' . v:count1 . 'g@_'<CR>
xno <silent> '#     :call <SID>op_list_digit()<CR>

Es funktioniert auch im visuellen Modus.
Ex-Befehle eignen sich gut für Skripte, aber für eine interaktive Verwendung ist ein normaler Operator wahrscheinlich besser, da Sie ihn mit jeder Bewegung oder jedem Textobjekt kombinieren können.

Sie können beispielsweise eine Liste mit Sternchen oder Minuszeichen innerhalb des aktuellen Absatzes umschalten, indem Sie auf tippen '*ip. Hier '*ist ein Operator und ipist das Textobjekt, an dem es arbeitet.

Machen Sie dasselbe für eine Liste, der in den nächsten 10 Zeilen Zahlen vorangestellt sind, indem Sie auf drücken '#10j. Hierbei '#handelt es sich um einen anderen Operator und 10jum eine Bewegung, die die Linien abdeckt, auf denen der Operator arbeitet.

Der andere Vorteil der Verwendung eines benutzerdefinierten Operators besteht darin, dass Sie Ihre letzte Ausgabe mit dem Befehl dot wiederholen können.

Bildbeschreibung hier eingeben

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.