Replace one word in searched result vim - vim

Is it possible to replace a section in the searched result? for example I have currently
<stringProp name="Argument.name">revision_no</stringProp>
<stringProp name="Argument.value">1</stringProp>
I want to replace the number (1) with ${var} on the 2nd line, and all other information remains the same.
If I type
:%s/revision_no<.*\n.*value">[0-9]\*/revision_no<(all the characters...) value">${var}/g
I might lose all the format(indentation involved)..
So I am wondering if there is a way to just replace "1" with ${var} in the whole search result.
`

You can capture the other matching text (that you want to keep), and then reference that exact text in the replacement. The \(...\) is a capture group (:help /\(), and \1 references it (the first such group) in the replacement. This is the traditional way, and it also works in sed and many other regular expression-based tools:
:%s/\(revision_no<.*\n.*value">\)[0-9]\+/\1${var}/g
Alternatively, in Vim, you can assert that certain surrounding stuff matches without actually including it in the match. This "cutting" is done via \zs (start match here) and \ze (end match here):
:%s/revision_no<.*\n.*value">\zs[0-9]\+/${var}/g

Related

vi replaces with empty when searching

In vi (from cygwin), when I do searching:
:%s/something
It just replaces the something with empty string like
:%s/something// .
I've googled for a while but nothing really mentions this. Is there anything I should add to the .vimrc or .exrc to make this work?
Thanks!
In vi and vim, when you search for a pattern, you can search it again by simply typing /. It is understood that the previous pattern has to be used when no pattern is specified for searching.
(Though, you can press n for finding next occurence)
Same way, when you give a source (pattern) and leave the replacement in substitute command, it assumes that the replacement is empty and hence the given pattern is replaced with no characters (in other words, the pattern is removed)
In your case, you should understand that % stand for whole file(buffer) and s for substitute. To search, you can simply use /, followed by a pattern. To substitute , you will use :s. You need not confuse searching and substituting. Hence, no need for such settings in ~/.exrc. Also, remember that / is enough to search the whole buffer and % isnt necessary with /. / searches the entire buffer implicitly.
You may also want to look at :g/Pattern/. Learn more about it by searching :help global or :help :g in command line.
The format of a substitution in vim is as follows:
:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]
In your case you have omitted the string from the substitution command and here what vim documentation stated about it:
If the {string} is omitted the substitute is done as if it's empty.
Thus the matched pattern is deleted. The separator after {pattern}
can also be left out then. Example: >
:%s/TESTING This deletes "TESTING" from all lines, but only one per line.
For compatibility with Vi these two exceptions are allowed:
"/{string}/" and "\?{string}?" do the same as "//{string}/r".
"\&{string}&" does the same as "//{string}/".
E146
Instead of the '/' which surrounds the pattern and replacement string, you can
use any other single-byte character, but not an alphanumeric
character, '\', '"' or '|'. This is useful if you want to include a
'/' in the search pattern or replacement string. Example: >
:s+/+//+
In other words :%s/something and :%s;something or :%s,something have all the same behavior because the / ; and , in the last examples are considered only as SIMPLE SEPARATOR

What does \#<= and \#= mean in Vim command?

Can't understand \#<= and \#= Benoit's answer of this post, anyone can help explain them?
From vim documentation for patterns
\#= Matches the preceding atom with zero width. {not in Vi}
Like "(?=pattern)" in Perl.
Example matches
foo\(bar\)\#= "foo" in "foobar"
foo\(bar\)\#=foo nothing
*/zero-width*
When using "\#=" (or "^", "$", "\<", "\>") no characters are included
in the match. These items are only used to check if a match can be
made. This can be tricky, because a match with following items will
be done in the same position. The last example above will not match
"foobarfoo", because it tries match "foo" in the same position where
"bar" matched.
Note that using "\&" works the same as using "\#=": "foo\&.." is the
same as "\(foo\)\#=..". But using "\&" is easier, you don't need the
braces.
\#<= Matches with zero width if the preceding atom matches just before what
follows. |/zero-width| {not in Vi}
Like '(?<=pattern)" in Perl, but Vim allows non-fixed-width patterns.
Example matches
\(an\_s\+\)\#<=file "file" after "an" and white space or an
end-of-line
For speed it's often much better to avoid this multi. Try using "\zs"
instead |/\zs|. To match the same as the above example:
an\_s\+\zsfile
"\#<=" and "\#<!" check for matches just before what follows.
Theoretically these matches could start anywhere before this position.
But to limit the time needed, only the line where what follows matches
is searched, and one line before that (if there is one). This should
be sufficient to match most things and not be too slow.
The part of the pattern after "\#<=" and "\#<!" are checked for a
match first, thus things like "\1" don't work to reference \(\) inside
the preceding atom. It does work the other way around:
Example matches
\1\#<=,\([a-z]\+\) ",abc" in "abc,abc"

How to perform following search and replace in vim?

I have the following string in the code at multiple places,
m_cells->a[ Id ]
and I want to replace it with
c(Id)
where the string Id could be anything including numbers also.
A regular expression replace like below should do:
%s/m_cells->a\[\s\(\w\+\)\s\]/c(\1)/g
If you wish to apply the replacement operation on a number of files you could use the :bufdo command.
Full explanation of #BasBossink's answer (as a separate answer because this won't fit in a comment), because regexes are awesome but non-trivial and definitely worth learning:
In Command mode (ie. type : from Normal mode), s/search_term/replacement/ will replace the first occurrence of 'search_term' with 'replacement' on the current line.
The % before the s tells vim to perform the operation on all lines in the document. Any range specification is valid here, eg. 5,10 for lines 5-10.
The g after the last / performs the operation "globally" - all occurrences of 'search_term' on the line or lines, not just the first occurrence.
The "m_cells->a" part of the search term is a literal match. Then it gets interesting.
Many characters have special meaning in a regex, and if you want to use the character literally, without the special meaning, then you have to "escape" it, by putting a \ in front.
Thus \[ and \] match the literal '[' and ']' characters.
Then we have the opposite case: literal characters that we want to treat as special regex entities.
\s matches white*s*pace (space, tab, etc.).
\w matches "*w*ord" characters (letters, digits, and underscore _).
(. matches any character (except a newline). \d matches digits. There are more...)
If a character is not followed by a quantifier, then exactly one such character matches. Thus, \s will match one space or tab, but not fewer or more.
\+ is a quantifier, and means "one or more". (\? matches 0 or 1; * (with no backslash) matches any number: zero or more. Warning: matching on zero occurrences takes a little getting used to; when you're first learning regexes, you don't always get the results you expected. It's also possible to match on an arbitrary exact number or range of occurrences, but I won't get into that here.)
\( and \) work together to form a "capturing group". This means that we don't just want to match on these characters, we also want to remember them specially so that we can do something with them later. You can have any number of capturing groups, and they can be nested too. You can refer to them later by number, starting at 1 (not 0). Just start counting (escaped) left-parantheses from the left to determine the number.
So here, we are matching a space followed by a group (which we will capture) of at least one "word" character followed by a space, within the square brackets.
Then section between the second and third / is the replacement text.
The "c" is literal.
\1 means the first captured group, which in this case will be the "Id".
In summary, we are finding text that matches the given description, capturing part of it, and replacing the entire match with the replacement text that we have constructed.
Perhaps a final suggestion: c after the final / (doesn't matter whether it comes before or after the 'g') enables *c*onfirmation: vim will highlight the characters to be replaced and will show the replacement text and ask whether you want to go ahead. Great for learning.
Yes, regexes are complicated, but super powerful and well worth learning. Once you have them internalized, they're actually fairly easy. I suggest that, as with learning vim itself, you start with the basics, get fluent in them, and then incrementally add new features to your repertoire.
Good luck and have fun.

replacing part of regex matches

I have several functions that start with get_ in my code:
get_num(...) , get_str(...)
I want to change them to get_*_struct(...).
Can I somehow match the get_* regex and then replace according to the pattern so that:
get_num(...) becomes get_num_struct(...),
get_str(...) becomes get_str_struct(...)
Can you also explain some logic behind it, because the theoretical regex aren't like the ones used in UNIX (or vi, are they different?) and I'm always struggling to figure them out.
This has to be done in the vi editor as this is main work tool.
Thanks!
To transform get_num(...) to get_num_struct(...), you need to capture the correct text in the input. And, you can't put the parentheses in the regular expression because you may need to match pointers to functions too, as in &get_distance, and uses in comments. However, and this depends partially on the fact that you are using vim and partially on how you need to keep the entire input together, I have checked that this works:
%s/get_\w\+/&_struct/g
On every line, find every expression starting with get_ and continuing with at least one letter, number, or underscore, and replace it with the entire matched string followed by _struct.
Darn it; I shouldn't answer these things on spec. Note that other regex engines might use \& instead of &. This depends on having magic set, which is default in vim.
For an alternate way to do it:
%s/get_\(\w*\)(/get_\1_struct(/g
What this does:
\w matches to any "word character"; \w* matches 0 or more word characters.
\(...\) tells vim to remember whatever matches .... So, \(w*\) means "match any number of word characters, and remember what you matched. You can then access it in the replacement with \1 (or \2 for the second, etc.)
So, the overall pattern get_\(\w*\)( looks for get_, followed by any number of word chars, followed by (.
The replacement then just does exactly what you want.
(Sorry if that was too verbose - not sure how comfortable you are with vim regex.)

VIM how to substitute with offset

The search command in vim allows you to place the cursor relative to the search results. For example, /hello/b+2 places the cursor on the first l.
How do I do that with the substitute command?
s/hello/b+2/_/
does not work.
I need this to replace not the entire search string, but a portion of it only (specifically, to blank out all but the first character of a word).
You generally have two options: similar to other regex engines zero-width matches (though with different syntax):
:s/\(he\)\#<=llo/_/
or vim-specific “set the start of the match here”:
:s/he\zsllo/_/
. Also, there is a workaround which will look similar in almost every other regex engine:
:s/\(he\)llo/\1_/
: this captures text that should be unchanged and makes replacement include it.

Resources