Reputation: 60
I have HTML that looks like this
<form>
<input id="firstname" value=""/>
<input id="lastname" value=""/>
<input id="email" value=""/>
</form>
And I want to add name="{id-name}" to each input field (see example code below)
<form>
<input id="firstname" name="firstname" value=""/>
<input id="lastname" name="lastname" value=""/>
<input id="email" name="email" value=""/>
</form>
How can I do this with Vim?
I am trying
%s/id=".*"/\=submatch(0)/g
And it's resulting in two issues:
1) The search, searches from first quote to last quote. It should be searching from first quote to the next quote.
2.) The submatch(0)
is taking the full result of search. How can I isolate it to only the value between id="{value}"
?
I come across this issue a lot, figuring out this vim command could help save me a lot of time in the future. Mainly splitting search results into the submatch()
I have also seen people on stack use \1 \2
instead of submatch()
to store results, is that approach better?
Any help will be greatly appreciated! Thank you!
Upvotes: 3
Views: 5195
Reputation: 7679
My first thought is that this question would be more appropriate on the Vim Stack Exchange...
But I'll answer it here anyway
The first problem you are encountering is called greediness. The basic idea is that the *
quantifies is greedy, so it tries to match as much text as possible. A more in-depth explanation can be found here.
To fix this, you can simply use the non-greedy equivalent of *
, which is \{-}
. Since this is non-greedy, it tries to match as little text as possible. For example, look at this text:
"hello", "world", "test"
Running
:s/".*"
will remove everything, but
:s/".\{-}"
will only remove "hello"
To fix your second problem, you'll need to look into capturing groups. Basically, whatever you surround in parentheses will be put into group 1, then the next pair of parentheses will be group 2, and so on and so forth. By default, the entire matched pattern is placed in group 0.
I would also recommend not using the eval operator, that is \=
. This makes things needlessly verbose. Your example is exactly equivalent to
:%s/id=".*"/\0/g
Since \0
means group 0, \1
means group 1, etc.
So you could do this:
:%s/id="\(.\{-}\)"/\0 name="\1"/g
Now, just a few more minor tips:
You can use &
in place of \0
.
Using \v
turns on magicness so you can remove some backslashes (see :help /\v
)
Since you only want to replace one match per line, putting /g
at the end is unnecessary.
Putting this all together, I would recommend the following regex:
:%s/\vid=(.{-})/& name="\1"
Upvotes: 9