I'm learning how substitution works in Vim. And I find this example really weird to understand: :?a?,/b/s/bad/good
. I know what this command will do in general. But why use two question marks to wrap a
? What does it mean?
1 Answer
The command is composed of two parts:
:?a?,/b/ The range
s/bad/good The substitution command
You probably already know that the :s
command can take a range:
:s/bad/good
will do the substitution on the current line:%s/bad/good
will do the substitution on all the lines of the buffer- And
/pattern1/,/pattern2/s/bad/good
will perfom the substitution between the next line matchingpattern1
and the next one matchingpattern2
.
The help :h :range
gives us the different items we can use as a range:
Line numbers may be specified with: *:range* *{address}*
{number} an absolute line number
. the current line *:.*
$ the last line in the file *:$*
% equal to 1,$ (the entire file) *:%*
't position of mark t (lowercase) *:'*
'T position of mark T (uppercase); when the mark is in
another file it cannot be used in a range
/{pattern}[/] the next line where {pattern} matches *:/*
?{pattern}[?] the previous line where {pattern} matches *:?*
\/ the next line where the previously used search
pattern matches
\? the previous line where the previously used search
pattern matches
\& the next line where the previously used substitute
pattern matches
Take a particular note of ?{pattern}[?] the previous line where {pattern} matches
: this is what is used in your question.
Your command :?a?,/b/s/bad/good
will be applied to the lines between the previous line matching a
and the next one matching b
. To make the difference clear between //
and ??
here are two examples:
Take this file:
a
bad
b
bad
a
With you cursor on b
in line 3 if you use :?^a$?,/^b$/s/bad/good
you will get:
a
good
b
bad
a
Because line 1 is the previous one matching ?^a$?
and line 3 is the next one matching /^b$/
Now if you use :/^a$/,/^b$/s/bad/good
you will get
a
bad
b
good
a
Because the next line matching /^a$/
is line 5 and Vim know how to reverse the inverted ranges.
Note that in the range part of the command changing //
to ??
changes how the action behave. This is different than changing the /
characters in the substitution part of the command where s/bad/good/
, s?bad?good?
and s;bad;good
are all equivalent as explained in this question.
?
are in the range section of the command and if I understand:h :range
properly they reference to?{pattern}[?] the previous line where {pattern} matches
which is not the same thing as what I asked in the question you linked.