快速计算一列数字的总数


15

我正在写一个降价表,看起来像这样:

| 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   |

我正在寻找一种快速计算第三列总计并将其插入缓冲区的方法。我想到的解决方案将使用可视块模式(选择所有数字)以及表达式寄存器(进行数学运算)。

使用本地Vim命令可以做到这一点吗?如果没有,是否有可以帮助我的插件?


1
您可以看一下这篇文章:vim.wikia.com/wiki/Using_vim_as_calculator
nobe4 2015年

Answers:


15

我写了一个插件:https : //github.com/sk1418/HowMuch ,它支持可视化选择并进行数学计算。

默认情况下,该插件支持三个数学表达式评估引擎:Gnu bc,python和vimscript。您可以对某一项进行计算,也可以让插件自动为您选择一种。

它适用于您的示例,如下所示:

在此处输入图片说明

有关详细信息,请阅读github上的自述文件。


如果您包括选择,求和和插入答案所需的击键,将很有帮助。
pdoherty926

@ pdoherty926 For details please read the README on github.即使我在这里输入了要解决此问题的按键,也看不出有多大用处,只是3或4个按键组合。如果某人确实需要我的脚本,他/她将始终检查详细信息。
肯特,

12

如果您不想使用插件或使用bash脚本,则可以执行以下操作:

  • c-V {motions} "ay 将列复制到 "a
  • :let @a = substitute(@a, 'c-V c-J', '+', 'g') 将列换行符替换为 +
  • ic-R=c-Ra"a通过表达式寄存器运行替换的

或者:使表达式历史记录条目可重复用于列的总和

  • ctrl-V {motions} y 将列放入猛拉寄存器 ""
  • ictrl-R=eval(substitute(@", '\n', '+', 'g'))

对另一列重复:

  • ctrl-V {motion} y (不变)
  • ictrl-R=<CR>或者,如果您对表达式寄存器做了其他操作,请使用向上箭头键(或ctrl-P重新映射)循环浏览历史记录:
    ictrl-R=<up>...<up><CR>

1
由于某些原因,我只设法在命令上使用双引号"而不是单引号来解决方案。您知道是否有任何原因吗?'substitute
vappolinario

@vappolinario对我来说都是双向的,所以我很抱歉,我不知道。
Hovercouch15年

@Hovercouch您能否详细说明第三步?确切地说,如何通过表达式寄存器运行替换?
pdoherty926

如何制作地图:`nnoremap <cs>:s / $ / \ = eval(substitute(@ 0,'[^ 0-9]','+','g'))/ <cr>`
SergioAraujo

9
:r!awk '{sum+=$6} END {print "Total: "sum}' %

说明:

: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

我一直在尝试在这里工作的功能:

" 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>

使用上面包含的地图,在加载该函数之后,您要做的就是选择要求和的数字,并用<leader>s其对所选区域求和。

功能说明:

它使用try/finally/endtry拉伸来捕获错误。

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

如果要尝试使用此功能,请执行以下操作:在浏览器中复制此功能,然后在vim上运行此命令,:@+ 这将使您可以:call SumVis()正常使用。

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

它需要您使用ctrl+ 进行可视块选择v,取消选择并最终调用该函数。或者,您可以使用建议的地图,它本身会在计算之前删除选择。



5

制作插件或在vimscript中编码似乎有点沉重。我相信无插件的vim,以及与外部工具的良好结合。

这是一次基于user257188​​1的1次命令,即使未保存缓冲区也可以使用。

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

如果要保存此命令以备将来使用,则可能要命名它:

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

它适用于视觉选择。如果选择几行并进入命令模式,vim将在命令前加上:'<,'>,这是可视选择的行范围。这样就可以运行:

:'<,'>SumColumn 3

并且只会汇总所选行的第三列。默认情况下,范围是%,因此

:SumColumn 3

将汇总所有行的第三列。

编辑:如果您希望能够指定其他字段分隔符并将默认列数计为最后一个,则可以覆盖命令bash并使用它来处理参数,如下所示:

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

现在,

:SumColumn

将使用“ |”计数表的最后一列 场分隔符

:SumColumn 3

将使用“ |”计数表的第三列 字段分隔符,以及

:SumColumn 3 +

将使用“ +”字段分隔符计算表格的第三列。


一个人如何处理其他可能的字段分隔符?只是为了使解决方案更通用。
SergioAraujo

@ user257188​​1,我已经编辑了答案,显示了这一点。
JoL

@JoL向SumColumnvimrc中添加函数意味着您只需在vimrc中包含“插件”即可。希望您擅长于随时间进行维护。对我来说,插件提供了文档,可以利用其他独创性分成有意义的部分。我为上游开发做出了贡献,改进了令人惊叹的插件,没有人有时间自己创建所有插件(tpope除外)。您是否不使用vim-surround,vim-fumitive,vim-easy-align / vim-lion,vim-unmpaired,vim-commentary,ultisnips或ft特定的工具(例如vim-go,vim-rails,vimtex)?
Hotschke

@Hotschke当我到达这里时,我看到了一个问题,并想:“好吧,只是通过awk。” 但是,然后,我看到了公认的答案是:“嘿,下载并安装数百个LOC插件。” 第三个答案是,“嘿,下载并安装数千个LOC插件。” 这太夸张了。即使您一生中需要多次对列求和,这也是过大的。我的答案旨在说明如何仅需执行一次就可以在单个无插件,无废话命令中执行此操作,以及如何在需要执行此操作的情况下使用带有参数的简单命令经常。
JoL

@Hotschke为了回答您的问题,我曾经将每个插件安装在看起来很凉爽的阳光下,但后来我的vim变得异常缓慢(请读“一点点懒”,这对于编辑器是无法忍受的)。在深入研究vim文档时,我意识到我并不需要插件。许多常用功能已经足够好了,对于vim所没有的功能,shell是必经之路。根据Unix哲学,从根本​​上讲(忽略它造成的异常),vim是一个与其他OS工具良好地互操作的编辑器。我相信这是最好地利用它的方式。此后没有插件。
JoL

2

如果列已正确对齐,则可以使用简单的oneliner完成。

  1. 首先以逐块可视化模式选择该列,因为其他答案已表明-> CTRL-V+移动光标
  2. 通过选择拉动选择 y
  3. 类型::echo eval(join(split(@", '\_s\+'), '+'))将在空格和换行符上拖动的文本分开,将元素与+字符重新连接,然后评估字符串。
  4. 另一种处理方法:用换行符替换+并求值::echo eval(substitute(@", "\n", '+', 'g'))- eval()reduce我们所拥有的最接近的东西。

如果不是,则必须使用其他技巧来计数字段。例如,split(getline('.'), "[ \t|]\\+")可用于从数组中的行拆分列。从那里开始,它变得非常简单:

  1. 在可视模式下选择线条
  2. :echo eval(join(map(getline("'<", "'>"), { -> split(v:val, "[ \t|]\\+")[2] }), '+'))

为了摆脱魔法值(字段号-1和+),它可以成为命令

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

可用于:

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

注意:这里我使用Vim 7.4.1xxx中的lambdas


1

Damian Conway的++插件中vmath的vmap

  1. github(仅178 sloc)安装插件,例如

    $ wget https://raw.githubusercontent.com/thoughtstream/Damian-Conway-s-Vim-Setup/master/plugin/vmath.vim -P ~/.vim/pack/manual/start/damians-tools/plugin
    
  2. 将映射添加到您的vimrc

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

    但是,我建议使用其他方法,例如 gA

  3. 移至第三2f|列并在可视块模式下选择列<C-V>G$
  4. ++(或您选择的映射)
  5. 显示结果并将其存储在寄存器中(总和为s
  6. 从寄存器中插入和s,例如"sp

有关此插件的演示,请参见YouTube视频Damian Conway,“更多即时更好的Vim”-OSCON 2013(从第29分钟开始)。


1

外部CLI工具csvstatcsvkit

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

选项的简短说明

  • -d DELIMITER输入CSV文件的定界字符。在这里|
  • -H 指定输入的CSV文件没有标题行。
  • -c COLUMNS以逗号分隔的要检查的列索引或名称的列表。默认为所有列。
  • --sum 仅输出和。

该工具还提供最小值,最大值,平均值,中位数,stdev(标准差),计数唯一值,频繁值列表。

插入文件

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

安装

在macOS 上,可以通过自制软件和在Debian / Ubuntu上使用csvkit,并且可以使用来安装$ sudo apt install csvkit

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.