Say we want to replace some values in a file; however, rather than performing a direct replacement, we are interested in replacing values based on their relative position—to their containing objects, or within certain patterns accompanying each of them.

For example, the following file contains some information in a typical fortran structure:

!- An example with objects and variables

Object A,  !- Some comment or additional label for objects
 Name A1,  !- Name of object
      10,  !- First variable in object
       9,  !- Second variable in object
       8,  !- Third variable in object
       7;  !- Fourth variable in object

Object A,  !- Some comment or additional label for objects
 Name A2,  !- Name of object
      20,  !- First variable in object
      19,  !- Second variable in object
      18,  !- Third variable in object
      17;  !- Fourth variable in object

Object A,  !- Some comment or additional label for objects
 Name A3,  !- Name of object
      10,  !- First variable in object
      19,  !- Second variable in object
       8,  !- Third variable in object
      17;  !- Fourth variable in object

Object B,  !- Some comment or additional label for objects
 Name B1,  !- Name of object
      20,  !- First variable in object
       9,  !- Second variable in object
       8,  !- Third variable in object
       7;  !- Fourth variable in object

Object C,  !- Some comment or additional label for objects
 Name C1,  !- Name of object
      10,  !- First variable in object
       9,  !- Second variable in object
      18,  !- 3rd variable in object
       7;  !- Fourth variable in object

Object C,  !- Some comment or additional label for objects
 Name C2,  !- Name of object
      30,  !- First variable in object
       9,  !- Second variable in object
       8,  !- Third variable in object
       7;  !- Fourth variable in object

And we want to replace the first variable in objects A and B, with 55.

To this end, we need to: 1. Define the logic 2. Translate the logic to a regex command 3. Manage the repetition of this logic.

1. Define the logic

One way of doing this would be to search fo the common pattern: “First variable in object”, and then check if it is contained in either “Object A” or “Object B”.

Or the other way round, to search for “Object A” or “Object B” and delimit the pattern to the presence of “First variable in object”.


Let’s use the second alternative. First we need to find “Object A” or “Object B”, followed by any text. Second we need to stop the search until the pattern “First variable in object” appears. Because the later pattern appears multiple times, we delimit the second search to a range of lines so it doesn’t match a pattern in the following object.

2. Translate the logic to regex command

A line with “Object A” or “Object B”, followed by any text:

/Object [BC].*\n
[BC] : B or C character
\n   : a newline character (line ending)

Stop until the pattern “First variable” appears, in a range of 6 lines.

.*\(\_s.*\)\{0,6\}\_sFirst variable
.*      : any character except new line, multiple times
\_s     : a whitespace (space or tab) or newline character
\{0,6\} : a range of 6 lines

The full regular expression:

/Object [BC].*\n .*\(\_s.*\)\{0,6\}\_sFirst variable

3. Manage the repetition of this logic.

We record a macro (in t) to make the substitution.

qt
/Object [BC].*\n .*\(\_s.*\)\{0,6\}\_sFirst variable
2jwcw55<esc>j
q
2j    : move two lines down
w     : move one word
cw    : change word
55    : new value
<esc> : return to command mode
j     : move one line down

And recursively run the macro in the file

:%normal @t

Let’s now replace the third variable in all objects with 99.

qt
/Object.*\n .*\(\_s.*\)\{0,3\}\_svariable
2jwcw55<esc>j
q
:%normal @t

I hope this has been useful.