I want to use regex capture groups with :substitute
in Neovim but they don't seem to be working.
For example, I have this text:
- myKey: myValue
I want it to be:
- myKey: something-myValue
I enter the following:
:s/(myKey:\s*)(.*)/$1something-$2/
I get:
E486: Pattern not found: (myKey:\s*)(.*)
The same pattern works without using capture groups:
How do I enable capture groups in :substitute
in Neovim? Additionally, how do I reference numbered capture groups in Neovim? Some programs use $1
, $2
, etc., some use \1
, \2
, etc.
Different regular expressions dialects have different syntaxes. The one used by Vim (and Neovim) is described in whole under :help pattern
.
Parentheses are not considered as special characters out of the box, so your pattern:
(myKey:\s*)(.*)
will literally match something like this:
(myKey: )(dfsdfsidrtysdis)
but not something like that:
- myKey: myValue
which is pretty much the opposite of what you want.
To give them special meaning, you must escape them with a backslash:
\(myKey:\s*\)\(.*\)
Or you can use \v
(for "verymagic") at the beginning of your pattern to tell Vim to parse the pattern with a "verymagic" syntax:
\v(myKey:\s*)(.*)
See :help /magic
, :help \(
, and :help \v
, all under the aforementioned :help pattern
.
Note that using \v
systematically, even to the point of mapping /
to /\v
and so on, is quite tempting at first (and common) but it becomes counterproductive very quickly if you work with code so I would advise against that.
The replacement part of a substitution is not itself a regular expression pattern so it is documented elsewhere, under :help sub-replace-special
, in the larger :help change
. There, some characters have a special meaning. To reuse a capture group, use \1
, \2
, etc.
Your command should thus be either:
:s/\(myKey:\s*\)\(.*\)/\1something-\2/
or:
:s/\v(myKey:\s*)(.*)/\1something-\2/
Note that Vim's regular expressions dialect contains unique atoms that can make your life easier. In this case, :help \zs
and :help s/\&
would make the pattern and the replacement simpler and shorter:
:s/myKey:\s*\zs.*/something-&/
where:
myKey:\s*
is used for the matching but whatever it matches is left outside of the actual match,myValue
,&
.In this specific case, myKey
can even be ommited:
:s/:\s*\zs.*/something-&/
The regular version, with all the escaping is fine but it is noisy, and thus error-prone. It is also the longest to type.
The \v
version may be a little bit better than the regular version because it is more readable and thus less error-prone, and slightly shorter. But it still has the capture group overhead cost.
The \zs
version is better than both because it is even clearer, and thus less error-prone, while also being considerably shorter. And there is no capture group overhead anymore.
This overview of regular expressions in Vim is old but still relevant.