3

I have string lets say

count number of elecment when tra(XYixe0/en_in/old)='mid/2' rise='corse/2'

I want to replace / from (XYixe0/en_in/old) to .

My output string should look like

count number of elecment when tra(XYixe0.en_in.old)='mid/2' rise='corse/2'

In summary, I want vim search / only on string which is inside () and replace / by .

Any help is appreciated.

1
  • See also my answer on the duplicate about using Visual mode to mark the part where you want to replace and the \%V marker to only replace inside the last Visual mode marked block.
    – filbranden
    Sep 28, 2019 at 14:35

4 Answers 4

2

Another way is to use a sub-replace-expression, \=:

:%s/([^)]*)/\=substitute(submatch(0),'\/','.','g')/

The :s/([^)]*)/{replacement}/ will match a pair of parens, ([^)]*). The {replacement} is \={expr}. Where {expr} will be a vimscript expression to be evaluated. In this case a substitution over the entire match, submatch(0), matching on \/ and replacing with . for the entire string, g.

For more help see:

:h sub-replace-expression
:h :s
:h substitute()
:h submatch()
2

It's not perfect since you have to run it multiple times to get every slash, but that's not too big of a problem:

:%s/(.*\zs\/\ze.*)/./g

This will replace one slash inside of parenthesis with a dot. To get it to replace all of them, you could then run something like

5@:

to get all of them replaced. (Adjust 5 to be as big as needed).

1

So this is a bit of a hack. If your inside the parenthesis

di(mmo^R"^[:s/\//./g^Mv$hxdd`m"-P

di( delete inside the parenthesis

mm make a mark so you can get back to your original position

^R" paste the " register into buffer from insert mode, that is ctrl+r

^[ is escape

:s/\//./g^M this is the substitution with ^M = enter

v$hx mark and delete your change this will also put it in the - register

dd will delete the line

`m that is backtick m (couldn't format that properly) which will take you back to the mark

"-P insert text from - register in before current char

0

The shortest path, not requiring repeat runs, is probably the (in)famous sub-replace expression.

A recent q&a asked a similar question regarding doing a replacement on just a portion of a line. In fact, they also wanted to operate on text inside parentheses. (This could arguably be considered a duplicate question...but I won't argue that here.) I posted a pretty extensive answer on using sub-replace expressions which is a method for running an arbitrary Vim expression as the replacement part of a substitution.

Some people find this approach complicated but I don't think it's too bad once you break it down....which I tried my best to do.

Briefly, either of these will work for your question...

:s#(\([^)]\+\))#\='(' . substitute(submatch(1), '/', '.', 'g') . ')'#

:s#(\zs\([^)]\+\)\ze)#\=substitute(submatch(1), '/', '.', 'g')#

And there are other variations, too. These are a little stretched out for readability (maybe). It also depends on how conservative/error-proof you want the solution to be.

Rather than repeat here what I said in that answer I suggest you read the original: How to run a substitute command on only a certain part of the line

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