The following solution works for me:
vnoremap <silent><expr> <c-x> YankAndAnalyse()
nmap <silent> <c-x> vip<c-x><esc>
function! YankAndAnalyse()
return 'y'
\ . ":call Analyse()\<CR>"
\ . ":silent normal! gv\<CR>"
endfunction
function! Analyse()
let selection = split(getreg(''), '\n')
let numbers = map(selection,
\ 'matchstr(v:val, ''\[\s*\zs\d\+\%(\.\d\+\)\?\ze\s*u\s*]'')')
call filter(numbers, '!empty(v:val)')
call map(numbers, 'str2float(v:val)')
if empty(numbers) | return | endif
echohl Identifier
echon 'Sum: ' . printf('%g', eval(join(numbers, ' + ')))
echohl None
endfunction
Here YankAndAnalyse
is a simple wrapper function that first fills the default register. Analyse
reads the default register and parses the numbers that match your critera. The YankAndAnalyse
function is mapped to CTRL-x
in visual mode (feel free to choose whatever you want), and the normal mode map simply applies the visual mode map to the current paragraph.
See the documentation for more help, e.g. :h matchstr()
for help on the matchstr
function.
Update: The above solution only sums the first matched number in each line. In order to sum all matched numbers, one may use the following version of the Analyse
function:
function! Analyse()
let input = getreg('')
let sum = 0
let n = 1
let new = matchstr(input, '\[\s*\zs\d\+\%(\.\d\+\)\?\ze\s*u\s*]', 0, n)
while !empty(new)
let n += 1
let sum += str2float(new)
let new = matchstr(input, '\[\s*\zs\d\+\%(\.\d\+\)\?\ze\s*u\s*]', 0, n)
endwhile
echohl Identifier
echon 'Sum: ' . printf('%g', sum)
echohl None
return
endfunction