1

I am just trying to replace several arithmetic expressions inside a script file, which I cannot seem to find a simple solution for on the web. Adapting this answer did not do the trick.

Suppose I have the following, very simple file test.py:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
u1 = [13 - 1];
u2 = [ 9 - 1];
print(u2)

I already tried (from the bash):

awk '{while(match($0, /([0-9]+)\-([0-9]+)/, m)) sub(/([0-9]+)\-([0-9]+)/, m[1] - m[2]) } 1' test.py

which does not seem to do anything. The following command

perl -pe 's/([\d+)\-(\d+])/$1-$2/ge' test.py

gives

#!/usr/bin/env python3
# 0*0 coding: utf08 0*0
u1 = [13 0 1];
u2 = [ 9 0 1];
print0u20

so not really what I want, not even valid code.

Inside Vim, I selected the text in visual (block) mode and piped it into bc or bc -l using !, which gives

(standard_in) 1: syntax error

though it used to work if the whole line just was 13 - 1, instead of u1 = [13 - 1];

Does anyone have a suggestion of a working solution which I could just apply on the whole file, which would replace any occurrence of [n - 1], [nn - 1] and [ n - 1] by the corresponding arithmetic result, retaining the square brackets?

1 Answer 1

1

Here's one solution: vi[s<C-r>=eval(@")<cr><esc>. You can probably xnoremap the bit after s. How?

  • vi[ select expression
  • s delete it, go to Insert mode
  • <C-r>=…<CR> insert result of the expression
    • eval(@") evaluate the text in the default register, which is what we just deleted when we pressed s
  • <esc> exit Insert mode

Note that this evaluates the expression like Vimscript, so beware of subtle differences and possible security holes.


Note that the :! filter is linewise. To use it here, I would run

:substitute/\[/&\r/ | substitute/]/\r&
k!!bc<CR>va[J

to split the brackets across lines, run the expression on its own line through bc, then rejoin all the brackets. (With tpope's surround plugin, the first line is just cS[[.

2
  • Ok nice. The first command vi...<esc> works well, I was able to record a macro with it. The second command :s/...& does the split, but then the third one k!!...J throws an error /bin/bash: -c: line 0: unexpected EOF while looking for matching `]'. Also, I understand both commands would work as long as the brackets are nicely aligned, as is the case in the testfile. But sometimes, those expressions also occur multiple times on the same line. Is there no way to combine them with one call to search&replace? I already have the regex to match the search, but still missing the replace.
    – winkmal
    Aug 23, 2022 at 7:31
  • @winkmal woops, I forgot a <CR> in the !!bc command; fixing. As for multiples, you could try the g flag as in :s/\[/&\r/g | s/]/\r&/g
    – D. Ben Knoble
    Aug 23, 2022 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.