我正在写下一个如下所示的减价表:

| 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命令是否可能?如果没有,是否有可以帮助我的插件?

评论

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

#1 楼

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

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

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



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

评论


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

– pdoherty926
17年4月4日在16:32

@ pdoherty926有关详细信息,请阅读github上的自述文件。即使我在此处输入了要解决此问题的按键,也看不出它有多大用处,只是3或4个按键组合。如果某人确实需要我的脚本,他/她将始终检查详细信息。

–肯特
17年12月4日在16:46

#2 楼

如果您不想使用插件或拖放到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>



评论


由于某种原因,我只设法在您的替代命令上使用双引号“而不是单引号”。

–vappolinario
2015年9月10日19:52



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

– Hovercouch
2015年9月10日20:17在

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

– pdoherty926
17年4月4日在16:09

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

– SergioAraujo
19年7月3日在17:35

#3 楼

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


说明:

:r ........... read (put result in this file)
! ............ external command
awk .......... external tool
{sum+=} .... 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进行可视块选择,取消选择并最终调用该函数。或者,您可以使用建议的地图,它本身会在计算之前删除选择。

#4 楼

我的csv插件允许这样做。使用:SumCol命令,并确保已阅读文档。

#5 楼

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

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

:%!awk -F '|' '{print; sum+=}; 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 +


将计算带有“ +”字段分隔符的表的第三列。

评论


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

–塞尔吉奥·阿劳霍(Sergio Araujo)
17年9月15日在15:59

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

– JoL
17年9月15日在16:32

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

–霍奇克
18年7月26日在10:54

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

– JoL
18年7月26日在15:31

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

– JoL
18年7月26日在15:32



#6 楼

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


首先以逐块可视化模式选择列,因为其他答案已经证明了-> CTRL-V +移动光标
y取消选择

类型::echo eval(join(split(@", '\_s\+'), '+')),它将在空格和换行符上拉的文本分开,用+字符重新加入元素,然后评估字符串。
另一种方法继续:用+替换换行符并求值::echo eval(substitute(@", "\n", '+', 'g'))-eval()是我们与reduce最接近的东西。

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


以可视模式选择行
: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。

评论


从8.2.0878开始,Vim提供了reduce()函数。因此,您也可以这样写:echo split(@“,'\ _s \ +')-> map(” str2float(v:val)“)-> reduce({a,v-> a + v})。

–user938271
20年6月23日22:30在

#7 楼

Damian Conway的插件++中的vmap vmath



从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



将映射添加到您的vimrc

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


但是,我建议使用其他东西,例如gA

移至第三列2f|并以可视块模式选择列<C-V>G$

++(或您选择的映射)
结果显示并存储在寄存器中(s中的总和)
从寄存器s中插入和,例如带有"sp


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

#8 楼

来自csvkit的外部cli工具csvstat


:!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上,可以通过自制程序及以下版本使用csvkit Debian / Ubuntu及其类似版本可以与$ sudo apt install csvkit一起安装。