Berechnen Sie schnell die Summe einer Zahlenspalte

15

Ich schreibe eine Markdown-Tabelle auf, die so aussieht:

| 13/05/15 | 09:30-16:00 |  6.5 |
| 14/05/15 | 10:00-16:30 |  6.5 |
| 16/05/15 | 15:30-01:00 |  9.5 |
| 21/05/15 | 09:00-16:30 |  7.5 |
| 22/05/15 | 08:30-17:00 |  8.5 |
| 28/05/15 | 09:30-15:30 |  6   |
| 02/06/15 | 09:00-20:00 | 11   |
| 03/06/15 | 08:30-22:30 | 14   |

Ich suche nach einer Möglichkeit, die Summe der dritten Spalte schnell zu berechnen und sie in den Puffer einzufügen. Die Lösung, an die ich denke, würde den Visual-Block-Modus (zum Auswählen aller Zahlen) und möglicherweise das Ausdrucksregister (zum Berechnen) verwenden.

Wäre dies mit nativen Vim-Befehlen möglich? Wenn nicht, gibt es ein Plugin, das mir helfen kann?

zool
quelle
1
Sie können sich diesen Artikel ansehen
nobe4

Antworten:

15

Ich habe ein Plugin geschrieben: https://github.com/sk1418/HowMuch, das die visuelle Auswahl unterstützt und mathematische Berechnungen durchführt.

Standardmäßig unterstützt das Plugin drei Bewertungsmodule für mathematische Ausdrücke: Gnu bc, Python und Vimscript. Sie können die Berechnungen für ein bestimmtes Plugin durchführen oder das Plugin automatisch eines für Sie auswählen lassen.

Es funktioniert mit Ihrem Beispiel so:

Bildbeschreibung hier eingeben

Für Details lesen Sie bitte die README auf Github.

Kent
quelle
Es wäre hilfreich, wenn Sie die erforderlichen Tastenanschläge zum Auswählen, Summieren und Einfügen in Ihre Antwort einfügen würden.
pdoherty926
@ pdoherty926 For details please read the README on github.Auch wenn ich die Tastenanschläge, die ich für dieses Problem gedrückt habe, hier eingebe , sehe ich nicht, wie hilfreich es sein könnte, es sind nur 3 oder 4 Tastenkombinationen. Wenn mein Skript wirklich von jemandem benötigt wird, wird er / sie die Details trotzdem überprüfen.
Kent
11

Wenn Sie keine Plugins verwenden oder kein Bash-Skript verwenden möchten, können Sie Folgendes tun:

  • c-V {motions} "ay Spalte kopieren in "a
  • :let @a = substitute(@a, 'c-V c-J', '+', 'g') Ersetzen Sie die Spalten-Zeilenumbrüche durch +
  • ic-R=c-RaFühren Sie das Ersetzte "adurch das Ausdrucksregister aus

Alternativ: Machen Sie den Ausdrucksverlaufseintrag für weitere Spaltensummen wiederverwendbar

  • ctrl-V {motions} y Spalte ins Ruckregister legen ""
  • ictrl-R=eval(substitute(@", '\n', '+', 'g'))

Wiederholen für eine andere Spalte:

  • ctrl-V {motion} y (unverändert)
  • ictrl-R=<CR>oder wenn Sie etwas anderes mit dem Ausdrucksregister gemacht haben, ctrl-Pblättern Sie mit der Aufwärtspfeiltaste durch den Verlauf (oder mit, wenn Sie ihn neu zugeordnet haben):
    ictrl-R=<up>...<up><CR>
Hovercouch
quelle
1
Aus irgendeinem Grund konnte ich Ihre Lösung nur mit doppelten Anführungszeichen "anstelle von einfachen Anführungszeichen 'für den substituteBefehl verwenden. Wissen Sie, ob es dafür einen Grund gibt?
Vappolinario
@vappolinario es funktioniert in beide Richtungen für mich, also fürchte ich, ich weiß es nicht, sorry.
Hovercouch
@Hovercouch Könnten Sie den dritten Schritt erläutern? Wie genau würde man die Ersetzung durch das Ausdrucksregister ausführen?
pdoherty926
Wie wäre es mit einer Karte: `nnoremap <cs>: s / $ / \ = eval (Ersatz (@ 0, '[^ 0-9]', '+', 'g')) / <cr>`
SergioAraujo
9
:r!awk '{sum+=$6} END {print "Total: "sum}' %

Erläuterung:

:r ........... read (put result in this file)
! ............ external command
awk .......... external tool
{sum+=$6} .... sixth field (awk considers spaces as field separator)
END .......... at the end
{print "Total: "sum} --> string "Total: " plus your result
% ............ current file

Ich habe eine Funktion ausprobiert, die hier funktioniert:

" This function requires you select the numbers
fun! SumVis()
    try
        let l:a_save = @a
        norm! gv"ay
        let @a = substitute(@a,'[^0-9. ]','+','g')
        exec "norm! '>o"
        exec "norm! iTotal \<c-r>=\<c-r>a\<cr>"
     finally
        let @a = l:a_save
     endtry
endfun
vnoremap <leader>s :<C-u>call SumVis()<cr>

Unter Verwendung der oben enthaltenen Karte müssen Sie nach dem Laden der Funktion nur die Zahlen auswählen, die Sie summieren möchten, und <leader>sden ausgewählten Bereich mit summieren.

Funktionserklärung:

Es verwendet try/finally/endtryExtruktur, um Fehler zu erfassen.

let l:a_save = @a .......... if whe have register 'a' we save it temporarelly
norm! gv"a  ................................... gv --> reselects and captures selection to 'register a'
let @a = substitute(@a,'[^0-9. ]','+','g') .... removes all but numbers, dots and spaces from 'register a' and puts '+' among the numbers
exec "norm! '>o"  ............................. opens new line bellow selection. see :h '>
exec "norm! iTotal: \<c-r>=\<c-r>a\<cr>" ...... insert "Total: " plus 'expression register result
let @a = l:a_save ............................. restores original 'a' register content

Wenn Sie diese Funktion ausprobieren möchten, gehen Sie wie folgt vor: Kopieren Sie diese Funktion in Ihren Browser und führen Sie diesen Befehl auf vim aus :@+ , damit Sie sie :call SumVis()normal verwenden können.

:@+ ......... loads `+` register making the function avaiable

Dazu muss man mit ctrl+ eine visuelle Blockauswahl treffen, die Auswahl vaufheben und schließlich die Funktion aufrufen. Alternativ können Sie die vorgeschlagene Karte verwenden, die die Auswahl vor der Berechnung entfernt.

SergioAraujo
quelle
7

Mein csv Plugin erlaubt dies. Verwenden Sie den :SumColBefehl und lesen Sie die Dokumentation.

Christian Brabandt
quelle
5

Ein Plugin zu erstellen oder dies in Vimscript zu kodieren, scheint ein bisschen schwer. Ich glaube an ein Plugin-freies Vim und eine gute Komposition mit externen Tools.

Hier ist ein einmaliger Befehl, der auf dem Befehl user2571881 basiert und auch dann funktioniert, wenn der Puffer nicht gespeichert wurde.

:%!awk -F '|' '{print; sum+=$4}; END {print "Total: "sum}'

Wenn Sie diesen Befehl für die zukünftige Verwendung speichern möchten, können Sie ihn benennen:

:command! -range=% -nargs=1 SumColumn <line1>,<line2>!awk -F '|' '{print; sum+=$('<args>' + 1)} END {print "Total: "sum}'

Es funktioniert mit visueller Auswahl. Wenn Sie einige Zeilen auswählen und in den Befehlsmodus wechseln, stellt vim Ihrem Befehl :'<,'>den Zeilenbereich für die visuelle Auswahl voran. So können Sie laufen:

:'<,'>SumColumn 3

und es wird nur die 3. Spalte der ausgewählten Zeilen summiert. Standardmäßig ist der Bereich %also

:SumColumn 3

summiert die 3. Spalte aller Zeilen.

BEARBEITEN: Wenn Sie in der Lage sein möchten, andere Feldtrennzeichen anzugeben und die Spalte standardmäßig bis zur letzten gezählt zu haben, können Sie den Befehl abdecken bashund die Argumente damit behandeln, wie folgt:

:command! -range=% -nargs=* SumColumn <line1>,<line2>!bash -c 'awk -F ${2:-|} "{print; sum+=\$(${1:-NF - 2} + 1)} END {print \"Total: \"sum}"' sumcolumn <args>

Jetzt,

:SumColumn

zählt die letzte Spalte einer Tabelle mit "|" Feldtrennzeichen,

:SumColumn 3

zählt die 3. Spalte einer Tabelle mit "|" Feldtrennzeichen und

:SumColumn 3 +

zählt die 3. Spalte einer Tabelle mit "+" Feldtrennzeichen.

JoL
quelle
Wie kann man mit anderen möglichen Feldtrennzeichen umgehen? Nur um die Lösung allgemeiner zu gestalten.
SergioAraujo
@ user2571881, Ich habe die Antwort bearbeitet und das gezeigt.
JoL
@JoL Funktionen wie SumColumnvimrc hinzuzufügen bedeutet, dass Sie einfach Ihre 'Plugins' in Ihrem vimrc haben. Hoffentlich sind Sie gut darin, dies mit der Zeit beizubehalten. Für mich liefern Plugins Dokumentation, Aufteilung in bedeutungsvolle Teile und nutzen den Einfallsreichtum anderer. Ich trage zum Upstream bei, der verblüffende Plugins verbessert, für die niemand Zeit hat, sie alle selbst zu erstellen (außer tpope). Verwenden Sie nicht Vim-Surround, Vim-Fugitive, Vim-Easy-Align / Vim-Lion, Vim-Unimpaired, Vim-Commentary, Ultisnips oder ft-spezifische wie Vim-Go, Vim-Rails, Vimtex?
Hotschke
@Hotschke Als ich hier ankam, sah ich die Frage und dachte: "Nun, pfeife einfach durch awk." Aber dann sah ich, dass die akzeptierte Antwort lautete: "Hey, lade dieses Hunderte von LOC-Plugins herunter und installiere es." Die dritte Antwort lautete: "Hey, lade dieses tausende von LOC Plugins herunter und installiere es." Es ist übertrieben und aufgebläht. Selbst wenn Sie Spalten mehr als einmal in Ihrem Leben summieren mussten, ist es übertrieben. Meine Antwort soll zeigen, wie Sie dies in einem einzigen no-plugins, no-nonsense-Befehl tun können, wenn Sie dies nur einmal tun müssen, und wie Sie einen einfachen Befehl mit Parametern daraus erstellen können, wenn Sie dies tun müssen häufig.
JoL
@Hotschke Um deine Frage zu beantworten, habe ich jedes Plugin unter der Sonne installiert, das aus der Ferne cool aussah, aber dann war mein vim unglaublich langsam (lies "ein wenig nach, was für einen Editor unerträglich ist"). Als ich mich genauer mit vim docs beschäftigte, stellte ich fest, dass ich die Plugins nicht wirklich brauchte. Viele der Aktienmerkmale waren gut genug, und für diejenigen, die Vim nicht hatten, war die Shell der richtige Weg. Grundsätzlich (Ausnahmen werden ignoriert) ist vim gemäß der Unix-Philosophie ein Editor, der gut mit anderen Betriebssystemwerkzeugen zusammenarbeitet. Ich glaube, das ist der beste Weg, um es zu nutzen. Keine Plugins seit.
JoL
2

Wenn die Spalten richtig ausgerichtet sind, kann dies mit einem einfachen Einzeiler erfolgen.

  1. Wählen Sie zuerst die Spalte im blockweisen visuellen Modus aus, wie andere Antworten gezeigt haben -> CTRL-V+ bewegen Sie den Cursor
  2. ziehe die Auswahl mit y
  3. type: :echo eval(join(split(@", '\_s\+'), '+'))teilt den Text in Leerzeichen und neue Zeilen auf, setzt das Element wieder mit einem +Zeichen zusammen und wertet die Zeichenfolge aus.
  4. Ein anderer Weg, um fortzufahren: Ersetzen Sie Zeilenumbrüche durch +und bewerten Sie: :echo eval(substitute(@", "\n", '+', 'g'))- eval()ist das Nächste, was reducewir haben.

Wenn nicht, müssen Sie andere Tricks anwenden, um Felder zu zählen. Zum Beispiel split(getline('.'), "[ \t|]\\+")kann verwendet werden , um die Spalten aus einer Zeile in der Matrix zu spalten. Von dort wird es so einfach wie:

  1. Wählen Sie Ihre Linien im visuellen Modus
  2. :echo eval(join(map(getline("'<", "'>"), { -> split(v:val, "[ \t|]\\+")[2] }), '+'))

Um die magischen Werte (Feldnummer - 1 und +) loszuwerden , kann es sich um einen Befehl handeln

:command! -range=% -nargs=+ OnField 
    \ echo { field, what -> eval(join(map(getline(<line1>, <line2>), { -> split(v:val, "[ \t|]\\+")[field-1] }), what))}(<f-args>)

Welches kann verwendet werden mit:

:OnField  3 +
:2,5OnField  3 +
:'<,'>Onfield 3 *   " after line-wise selection
....

Hinweis: Hier verwende ich Lambdas aus Vim 7.4.1xxx

Luc Hermitte
quelle
1

vmap ++vom Plugin vmathvon Damian Conway

  1. Installieren Sie das Plugin von Github (nur 178 Sloc) zB

    $ wget https://raw.githubusercontent.com/thoughtstream/Damian-Conway-s-Vim-Setup/master/plugin/vmath.vim -P ~/.vim/pack/manual/start/damians-tools/plugin
    
  2. Fügen Sie Ihrem vimrc eine Zuordnung hinzu

    vmap <silent><expr>  ++  VMATH_YankAndAnalyse()
    

    Ich würde jedoch vorschlagen, etwas anderes zu verwenden, z gA

  3. Gehen Sie zur dritten 2f|Spalte und wählen Sie die Spalte im Visual Block-Modus aus<C-V>G$
  4. Drücken Sie ++(oder Ihre gewählte Zuordnung)
  5. Ergebnisse werden angezeigt und in Registern gespeichert (Summe in s)
  6. Summe aus Register einfügen s, zB mit"sp

Eine Präsentation dieses Plugins finden Sie im YouTube-Video Damian Conway, "More Instantly Better Vim" - OSCON 2013 (ab Minute 29).

Hotschke
quelle
1

Externes CLI-Tool csvstatvon CSVKIT

:!csvstat -d '|' -H -c 4 --sum %
69.5

Kurze Erläuterung der Optionen

  • -d DELIMITERBegrenzungszeichen der CSV-Eingabedatei. Hier |.
  • -H Geben Sie an, dass die CSV-Eingabedatei keine Kopfzeile enthält.
  • -c COLUMNSEine durch Kommas getrennte Liste der zu untersuchenden Spaltenindizes oder Namen. Standardmäßig werden alle Spalten verwendet.
  • --sum Nur Ausgabesummen.

Dieses Tool bietet auch Min, Max, Mittel, Median, Standardabweichung (Standardabweichung), eindeutige Zählwerte und eine Liste mit häufigen Werten.

In Datei einfügen mit

<C-r>=system("csvstat -d '|' -H -c 4 --sum FILENAME 2> /dev/null")  

Installation

Unter macOS ist csvkit über Homebrew und unter Debian / Ubuntu verfügbar und kann mit ähnlichen Programmen installiert werden $ sudo apt install csvkit.

Hotschke
quelle