所以我有一个这样的文本文件:
Item a: <total>
Subitem: 10 min
Subitem 2: 20 min
Run Code Online (Sandbox Code Playgroud)
我想<total>用10和20的总数替换.现在我正在使用以下函数:
let g:S = 0 "result in global variable S
function! Sum(number)
let g:S = g:S + a:number
return a:number
endfunction
function! SumSelection()
let g:S=0
'<,'>s/\d\+/\=Sum(submatch(0))/g
echo g:S
endfunction
vnoremap <s-e> call SumSelection()<cr>
Run Code Online (Sandbox Code Playgroud)
Sum获取传入的数字总和,SumSelection调用所选行中所有数字的总和,并且(假设)Shift + e以可视模式调用SumSelection(或者您选择调用它的任何内容).
问题是,当我选择了一些行时按Shift + e,而不是:call SumSelection()我真正得到的:'<,'>call SumSelection(),这意味着每个选定行调用一次函数.不好,对吗?所以据我所知,没有办法解决这个问题.我该怎么做才能使功能:
198*_*983 19
好吧,要让函数在一个范围内执行一次,请附加range关键字.例如
fun Foo() range
...
endfun
Run Code Online (Sandbox Code Playgroud)
然后你的函数可以使用特殊参数a:firstline和a:lastline来处理范围本身.(详见:help a:firstline.)
但是我认为在这种情况下,您的要求非常简单,只需使用单线程即可完成:global.
我们可以做更好的指定输入和输出.但假设一个文件包含
Item a: <total>
Subitem: 10 min
Subitem 2: 20 min
Item b: <total>
Subitem: 10 min
Subitem 2: 23 min
Item c: <total>
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
Run Code Online (Sandbox Code Playgroud)
和定义为的函数
fun! Sum(n)
let g:s += a:n
return a:n
endfun
Run Code Online (Sandbox Code Playgroud)
然后这将总结子项(所有一行)
:g/^Item/ let g:s = 0 | mark a | +,-/\nItem\|\%$/ s/\v(\d+)\ze\s+min$/\=Sum(submatch(0))/g | 'a s/<total>/\=(g:s . ' min')/
并产生这个输出
Item a: 30 min
Subitem: 10 min
Subitem 2: 20 min
Item b: 33 min
Subitem: 10 min
Subitem 2: 23 min
Item c: 76 min
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
Run Code Online (Sandbox Code Playgroud)
顺便说一下,上面的命令作用于整个缓冲区.如果先突出显示一个范围然后按下该:键,vim将自动添加您的命令,'<,'>意味着以下命令将从突出显示的范围的开始到结束操作.
例如,突出显示第1行到第5行然后运行命令(:'<,'> g/...)会产生此输出
Item a: 30 min
Subitem: 10 min
Subitem 2: 20 min
Item b: 33 min
Subitem: 10 min
Subitem 2: 23 min
Item c: <total>
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
Run Code Online (Sandbox Code Playgroud)
最后一点说明.如果其中一个组没有子项,例如
Item a: <total>
Subitem: 10 min
Subitem 2: 20 min
Item b: <total>
Item c: <total>
Subitem: 10 min
Subitem 2: 23 min
Subitem 3: 43 min
Run Code Online (Sandbox Code Playgroud)
然后,当命令到达第二个项目时,该命令将以"无效范围"错误中止.您可以让Vim忽略它并继续执行,无论前缀是否为整个命令:silent!.
编辑
只是快速解释我的工作流程以及为什么长的单线程.
:g和ex命令很多.