vim search and append/modify - text

Is there a way to search for a text in vim and then modify, not just overwrite said text? i.e. if each occurrence matches certain pattern, I would like to replace each occurrence with unique text, partly based on characters next to occurrence the text that matches the pattern.
Specifically speaking, I'd like to do the following:
I'd like to replace text that matches the pattern /\*.png with /\*.png alt=* title=\* where * is the text that varies in each case.
Thanks in advance!

You can replace the results with parts of the match by using submatches. For instance, say you have the following html:
<img src="foo_one.png" />
<img src="bar_two.png" />
You can run this command:
:%s/"\(.\{-}\)\.png"/"\1.png" title="\1" alt="\1"/g
The .\{-} will match "any number of characters before the .png part, non-greedily" (:help /\{), and the brackets around it, \( and \) mark it as a captured group that will then be used in the substitution as \1 (the first captured group). Running this gives you:
<img src="foo_one.png" title="foo_one" alt="foo_one" />
<img src="bar_two.png" title="bar_two" alt="bar_two" />
Now, if you need a more complicated substitution, like turning the filename into a human-readable string, you could use the \= substitution flag to replace the string with any expression, like a function call. For instance, here's what we could run on the above text:
:%s/title="\zs\(.\{-}\)\ze"/\=lib#CamelCase(submatch(1))/g
This uses two Vim-specific patterns: \zs and \ze. Those are "match start" and "match end". The thing that will be searched for is the entire pattern, title=.... However, what will be replaced is only between \zs and \ze. This makes it easier to use the result of lib#CamelCase as a direct replacement.
Note that you don't need the \(/\) brackets this time around, because you can just use submatch(0) for "the entire match":
%s/title="\zs.\{-}\ze"/\=lib#CamelCase(submatch(0))/g
The function lib#CamelCase is my own function that's implemented like so:
function! lib#CamelCase(word)
return substitute(a:word, '_\(.\)', '\U\1', 'g')
endfunction
You can write any function that takes some input and returns a replacement string, doing whatever you need.
I'm not sure what your level of experience is with both Vim and regular expressions, so it's hard to give specific advice, and Vim substitutions are a big topic. I can recommend you read up on these help topics:
:help pattern-overview
:help sub-replace-special
:help sub-replace-expression

You can use the command line for that.
In Linux use sed.
sed -i 's/\.png/\.png alt=* title=*/g'
Here it is running a search on .pngand replace by .png alt=* title=*.
You must use the backslash before the . because it's a special character.

Related

Replace one word in searched result 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

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

How to write zero-width assertions in vim?

Here is the raw material I’m working with:
line1=a1 abc
line2=abc
line3=aba
line4=cbc
i want to match lines which do not contain character string of "abc" ,the result is :
line3=aba
line4=cbc
how can i get it in vim? maybe the expression is something such as (?!abc) in perl ,i am not sure how to write the regular expression in vim.
To match lines not ending with abc you could write the expression in two ways. My preferred is With very magic
/\v.*(abc)#!/
And with no very magic:
/.*\(abc\)\#!/
I recommend you to take some time to read:
:help magic
From Power Of G:
Delete all lines that do not match a pattern.
:g!/<pattern>/d
Of course, you can replace the d at the end to do something other than deleting the line...
It seems you're familiar with Perl regular expressions. You will probably be interested in :help perl-patterns where you can Vim equivalents for common Perl regex patterns. There, you can see that for a zero-width negative look-ahead, you want \#!.
For other zero-width patterns, including some not listed at :help perl-patterns, see :help /\#= and following. Also useful are \zs and \ze which can avoid some more complex zero-width matches in many cases.

How to search for a string containing a regex in Vim?

Is it possible to search a string that is a regex, without escaping all the fancy characters?
For example, I want to find this string in my source file: ^[\d\| *]$, without escaping \, $, etc.
I would like to just copy and paste the regex and get the result.
What you want is a grep that searches for matching strings, rather than attempting to match a regular expression. With GNU grep, you can invoke the command with the
-F or --fixed-strings flags, or just invoke the command as fgrep instead. The following are all equivalent:
grep -F '^[\d\| *]$'
grep --fixed-strings '^[\d\| *]$'
fgrep '^[\d\| *]$'
Fixed-string searches are exactly what you need when you want to match code that represents a regular expression, or when you want a faster grep that doesn't need the advanced matching capability of a regular expression engine.
There is an easy way to avoid special treatment of the characters
in Vim regular expressions. The \V specifier allows to switch
interpretation of the rest of the pattern to the “very nomagic” mode,
which means that every character but the backslash is understood
literally.
Therefore, one can set the last search register accordingly:
:let #/ = '\V' . escape('^[\d\| *]$', '\')
and use n and N for searching immediately.
You can use the command line tool fgrep (“fast grep”),
Supposing you have yanked the regexp to search for to the default register (#"), you can do this:
/\V<C-R><C-R>=escape(#", '/\')<CR><CR>
The \V starts a "very nomagic" search, where only atoms starting with a backslash have special, non-literal meaning. The escape() renders all those contained backslashes ineffective (and escapes / which would otherwise end the search pattern), so that this is a purely literal search. The text is inserted via Ctrl+R= into the search command line.

Vim Substitution

I always wanted to know, how you can substitute within given parameters.
If you have a line like this:
123,Hello,World,(I am, here), unknown
and you wnat to replace World with Foobar then this is an easy task: :%s/World/Foobar/
Now I wonder how I can get rid of a , which is wihtin the ( ).
Theoretically I just have to find the first occurance of ( then substitute the , with a blank until ).
Try lookahead and lookbehind assertions:
%s/([^)]*\zs,\ze.*)//
(\zs and \ze tell where pattern starts and end)
or
%s/\(([^)]*\)\#<=,\(.*)\)\#=//
The first one is more readable, the second one uses \( ... \) groupings with parentheses inside groups which makes it look like obfuscated, and \#<= which apart from being a nice ASCII-art duck is the lookbehind operator, and \#= that is the lookahead operator.
References: :help pattern (more detail at :help /\#=, :help /\ze, etc.)
You use the GUI and want to try those commands? Copy them into the clipboard and run :#+ inside Gvim.
Modifying slightly the answer of #Tom can give you a quite good and "a bit" more readable result :
%s/\(.*\)(\(.*\),\(.*\))\(.*\)/\1(\2\3)\4/
That way you will have : in \1 will store what is at the left outside of the parenthesis, \4 what is at the right outside of the parenthesis and \2 and \3 what is inside the parenthesis, respectively on the left (\2) and on the right (\3).
With that you can easily swap your elements if your file is organised as column.
You can also select the text you want to change (either with visual or visual-block modes) and enter the : to start the replace command. vi will automatically start the command with :'<,'> which applies the command to the selected area.
Replacing a , can be done with:
:'<,'>s/,/ /g
For your example, this is the same thing as suggested by #ubuntuguy
%s/\(.*\)(\(.*\),\(.*\)/\1(\2\3
This will do the exact replacement you want.
Yet another approach, based on the fact that actually you want to substitute only the first occurrence of , inside the parenthesis:
:%s#\((.\{-}\),#\1 #
Explanation:
:%s for substitution in the whole file (don't use % if you want to work only with the current line)
we can use # or : as a delimiter to make the command more readable
in (.\{-} we ask to find any symbol (dot) after the left parenthesis and the rest stands for 0 or more occurrence (as few as possible) of this symbol. This expression is put inside \(...\) to be able to refer to this group as \1 in the future.

Resources