3

I'm trying to substitute all non matching characters in a single line between certain columns (after a search).

Example:
The search can be everything
In example below the search = test
The substitute character of non matching characters: empty space.

I want to substitute all characters non part of "test" between columns 10 and 30.
Columns 10 and 30 are indicated with |

before:  djd<aj.testjal.kjetestjaja testlala ratesttsuvtesta !<-a-
                  |                   |   
after:   djd<aj.test       test     testlala ratesttsuvtesta !<-a-

How can I realize this?

Reman
  • 7,931
  • 11
  • 55
  • 97
  • 1
    I haven't proven this to myself yet, but I don't think that you can do this with regex alone. In order to exclude the first 10 characters, you're going to have to match against them in some way... once you do that match, they become eligible for your substitution. I think that you're better off splitting the string into three pieces, performing the substitution, then joining the pieces afterwards ...but I would love to be proved wrong. – Barton Chittenden Apr 10 '12 at 11:22
  • Sometimes 10 characters sometimes more or less characters. How would you divide the string in 3 pieces and put them together again? – Reman Apr 10 '12 at 12:49
  • If I was strictly staying in vim, I would simply add a linefeed where I wanted to break the line, make the substitution, then join the line again. If this was something that I was going to do on a regular basis, I would create a macro which would do the substitution and join the lines (making sure to remove extraneous spaces after the join). I like @Bernhard's method as well, but I've never tried it. – Barton Chittenden Apr 10 '12 at 13:13
  • @Barton: [The issue can be solved using Vim regular expression language and capabilities of the `:substitute` command.](http://stackoverflow.com/a/10101850/254635) – ib. Apr 11 '12 at 08:18

2 Answers2

3

Use the following substitution command on that line.

:s/\(test\)\zs\|\%>9v\%<31v./\=submatch(1)!=''?'':' '/g

If the range of columns is specified using visual selection, run

:'<,'>s/\(test\)\zs\|\%V./\=submatch(1)!=''?'':' '/g
ib.
  • 27,830
  • 11
  • 80
  • 100
  • thank you so much. I resolved all my things now with the columns! Just to understand better what do I have to change to do the contrary.. substitute only the letters in `test` between line 10 and 30? I just played a bit with it moved the `\zs` and changed other things but nothing worked. Thanks so much! – Reman Apr 11 '12 at 12:35
  • 1
    For the complementary problem, if the range of columns is known beforehand, use the command `:%s/\%>9vtest\%<32v/\=repeat(' ',strwidth(submatch(0)))/g`; if that range is specified with visual selection, use `:'<,'>s/\%Vtes\%Vt/\=repeat(' ',strwidth(submatch(0)))/g`. – ib. Apr 12 '12 at 00:55
1

One method may be to select the appropiate column range using the Visual mode (control+v)

Once selected, the search and replace can be done using (see this question)

 %s/\%Vfoo/bar/g

A regular expression for not test can be found here: Regular expression to match a line that doesn't contain a word?

Community
  • 1
  • 1
Bernhard
  • 3,619
  • 1
  • 25
  • 50